C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как пользоваться isdigit ?, проверка символа строки Memo
aquanet sk
Отправлено: 19.02.2007, 21:30


Станционный диспетчер

Группа: Участник
Сообщений: 87



Добрый ... всем!

На пол дня повис вот на какой проблеме: не могу проверить конкретный символ в строке Memo на его принадлежность к цифрам.

Тут 2 проблемы:
- не знаю, как вернуть/обратиться к конкретному символу в Memo
- не могу заюзать функцию isdigit для возвращаемого символа

CODE
for(int i=0;i<strlen( Memo1->Lines->Strings[current_string].c_str() );i++)
{
if( isdigit( Memo1->Lines->Strings[current_string][i] ) ){...}
}

этот код вызвал ошибку.

Отредактировано aquanet sk — 19.02.2007, 21:39
beginner
Отправлено: 19.02.2007, 22:01


Дежурный стрелочник

Группа: Участник
Сообщений: 44



В AnsiString символы индексируются с 1.
CODE
 int lines_cnt = Memo1->Lines->Count;
 for(int i = 0; i < lines_cnt; i++)
 {
   int n = Memo1->Lines->Strings[i].Length();
   for(int j = 1; j <= n; j++)
   {
     char c = Memo1->Lines->Strings[i][j];
     bool bDgt = (c <= '9' && c>='0');
     //...
     if(bDgt)
       ShowMessage(c);
   }
 }
aquanet sk
Отправлено: 19.02.2007, 23:20


Станционный диспетчер

Группа: Участник
Сообщений: 87



Да, AnsiString с 1, просто в программе у меня сейчас совсем другое, тут вручную набил с ошибочкой, сорри.rolleyes.gif Проблему я нашел, просто из скупердяйства наверное smile.gif использовал одну переменную в трех разных целях, ну и в общем накладочка всё таки была, как оказалось в ходе проверок.

beginner, спасибо, навел на мысль!

Вопрос по твоему коду, а почему всё именно так сделал: без использования isdigit, с подставнЫми переменными? Так быстрее?

Я просто сейчас ломаю голову, как ускорить обработку 11000 строк, что у меня в Memo, потому как уже через секунд 10-15 программа
перестает подавать признаки жизни (развисает через несколько минут). (Pentium 2,4 Ghz, 1GB RAM).
Может быть можно как-то притормаживать процесс обработки, чтобы программа не пожирала 70% проца?

Отредактировано aquanet sk — 19.02.2007, 23:24
beginner
Отправлено: 20.02.2007, 00:28


Дежурный стрелочник

Группа: Участник
Сообщений: 44



Конечно быстрее.

Ведь если написать напр.
for(int i = 0; i < Memo1->Lines->Count; i++)

тогда, каждый раз в конца цикла вычисляется значение Memo1->Lines->Count.
aquanet sk
Отправлено: 20.02.2007, 01:17


Станционный диспетчер

Группа: Участник
Сообщений: 87



А Memo1->Lines->Strings[i].Length(); как для цикла оптимизировать?

Мне надо её использовать в цикле каждый раз для сравнения длин строк (одна, текущая, д.б. меньше другой, заданной).
beginner
Отправлено: 20.02.2007, 01:56


Дежурный стрелочник

Группа: Участник
Сообщений: 44



QUOTE (aquanet sk @ 20.02.2007, 01:17)
А Memo1->Lines->Strings[i].Length(); как для цикла оптимизировать?

Мне надо её использовать в цикле каждый раз для сравнения длин строк (одна, текущая, д.б. меньше другой, заданной).

Если
CODE
   int n = Memo1->Lines->Strings[i].Length();
   for(int j = 1; j <= n; j++)
тогда Length() вызовется только раз.
AVC
Отправлено: 20.02.2007, 09:10


Ветеран

Группа: Модератор
Сообщений: 1583



По поводу скоростей работы с AnsiString посмотрите тему надо разбить AnsiString по запятым
aquanet sk
Отправлено: 20.02.2007, 14:24


Станционный диспетчер

Группа: Участник
Сообщений: 87



To beginner

C этим я понял (да в общем-то я всё в одну строку писал, чтобы вам меньше кода было просматривать).
Мне каждый раз именно сами строки надо сравнивать, т.е.
dlinaEtalona = AnsiStrokaEtalon.Length();
Memo1->Lines->Strings[0].Length()> dlinaEtalona?
Memo1->Lines->Strings[1].Length()> dlinaEtalona?
Memo1->Lines->Strings[2].Length()> dlinaEtalona?
и т.д.

А потом уже по тем строкам, что остануться, пройтись Вашим циклом, посимвольно сравнивая с "эталоном цифры".

Отредактировано aquanet sk — 20.02.2007, 17:58
aquanet sk
  Отправлено: 20.02.2007, 17:46


Станционный диспетчер

Группа: Участник
Сообщений: 87



To AVC, Даа, ребята там зажглиии smile.gif

Я так понимаю, самым быстрым оказался способ:
CODE
str = "";
for (int i=0; i < 2000; i++) str += AnsiString::StringOfChar('a',100) + ",";
done = 0;

for (char *cp=str.c_str(); *cp; cp++ )
if(*cp == ',')
{ if(++done > 8) break;
*cp = '\n';
}
...
/* 0.005 ----------------------------------------------------- */


Только в этом коде я мало понял, можно пояснить этот пример, чтобы я смог применить его к своей задаче?
Задача:
вход: 11000 строк в Memo (скопированы вручную с web -странички)
в каждой строке надо найти определнные символы (каждый раз разные) или содержащиеся в строке слова. Ну для примера возьмем слово "lesson", символы "+" и "t" и цифры от 0 до 9.
Выход: на выходе должны получить строки, в которых не содержался ни один из вышеперечисленных критериев.
Т.е. задача заключается в удалении всех строк, содержащих символы "+", "t", слово "lesson" и цифры от 0 до 9.

В частности в приведенном примере не понял строки
for (int i=0; i < 2000; i++) str += AnsiString::StringOfChar('a',100) + ",";
Откуда цифры 2000, 100, и что вообще делает эта строка с буфером данных AnsiString'а.
И не понял приема, когда в условии цикла стоит *cp, как это действует?
Помогите разобраться, пожалуйста.

P.S. А что скажете по поводу функции isdigit? Она тоже достаточно сильно, как и Pos, будет тормозить?

Отредактировано aquanet sk — 20.02.2007, 18:40
AVC
Отправлено: 20.02.2007, 18:09


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE (aquanet sk @ 20.02.2007, 16:46)
Я так понимаю, самым быстрым оказался способ...

Там было всего два способа. А это частный случай способа 1 для первых 8-ми запятых

QUOTE

...
в приведенном примере не понял строки
for (int i=0; i < 2000; i++)  str += AnsiString::StringOfChar('a',100) + ",";
Откуда цифры 2000, 100, и что вообще делает эта строка с буфером данных AnsiString'а.

Это код создает тестовый буфер, состоящий из 2000 фрагментов из 100 символов а и запятой после них.

QUOTE

И не понял приема, когда в условии цикла стоит *cp, как это действует?
Помогите разобраться, пожалуйста.

Это не очень честный, но допустимый прием, позволяющий работать с внутренним буфером AnsiString как с массивом asciiz.

По поводу основного вопроса — если еще будет нужно завтра (если будет возможность) поробую набросать код. Какое максимальное время планируется на поиск всех строк?
aquanet sk
Отправлено: 20.02.2007, 18:39


Станционный диспетчер

Группа: Участник
Сообщений: 87



Вы знаете, рассчитываю на максимально быстрое время (этот пример думаю как раз максимально быстрое время и дает), потому что будет вставляться в Memo за раз до 10-ти web-страничек, в каждой из которых 11000-14000 строк. И ждать десятки минут бессмысленно конечно. По хорошему хотелось бы одну страничку обрабатывать не более 30 секунд, но у меня в этом опыта нет и не знаю даже на вскидку, сколько приблизительно этот процесс может занимать. С моими Pos и isdigit одна страничка обрабатывается от 1мин 45сек до полного зависания программы, что совсем не катит, очень важно, чтобы программа при такой большой загрузке процессора компьютера всё таки довела обработку до конца, а не "испарилась" ( программа работает в фоновом режиме ) в неизвестный момент времени, и ищи её потом в Task Manager.

Спасибо, буду ждать!

Отредактировано aquanet sk — 20.02.2007, 19:37
beginner
Отправлено: 20.02.2007, 18:59


Дежурный стрелочник

Группа: Участник
Сообщений: 44



QUOTE (aquanet sk @ 20.02.2007, 17:46)
Задача:
вход: 11000 строк в Memo (скопированы вручную с web -странички)
в каждой строке надо найти определнные символы (каждый раз разные) или содержащиеся в строке слова. Ну для примера возьмем слово "lesson", символы "+" и "t" и цифры от 0 до 9.
Выход: на выходе должны получить строки, в которых не содержался ни один из вышеперечисленных критериев.
Т.е. задача заключается в удалении всех строк, содержащих символы "+", "t", слово "lesson" и цифры от 0 до 9.

Мне кажется, что в постановлении задачи, что-то явно не то.
Хотя бы взять условие, что нужно удалить строку полностью, если она
напр. содержит слово lesson. Но в HTML-ских строках часто команды
форматирования и то что выводится на экран находятся в одной строке.
А условие удаления строк содержащих цифры, вообще не понятно, ведь тогда напр. такая строка:

tаble width='95%' bоrder='0' align='center' bgcolor='white'

из-за 9-и тоже будет удалена.

Отредактировано beginner — 23.02.2007, 13:48
AVC
Отправлено: 21.02.2007, 17:56


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

вход: 11000 строк в Memo (скопированы вручную с web -странички)
в каждой строке надо найти определнные символы (каждый раз разные) или содержащиеся в строке слова. Ну для примера возьмем слово "lesson", символы "+" и "t" и цифры от 0 до 9.
Выход: на выходе должны получить строки, в которых не содержался ни один из вышеперечисленных критериев.


Для эксперимента был взят текст книги "Бьерн Страуструп. Язык программирования С++"
Размер файла 1.085.810 байт, 25.160 строк
из исходного текста удалялись строки, содержащие кроме приведенных условий еще и те где есть последовательности "class" и "ссылка"
Пока крутился цикл на компьютере выполнялась и другая, текущая, работа.
Результат эксперимента
QUOTE

Всего циклов 283 последний 2.45 s
строк до/после 25159/17618
среднее время 2.78 s

думаю можно считать удовлетворительным.

Собственно сам код
CODE

//---------------------------------------------------------------------------

AnsiString __fastcall Delete_Prohibited_Lines
(const AnsiString &itext // вход
,const char *prh_chars // запрещенные символы
,char **prh_words // список запрещенных слов (ограничен NULL)
);

//- — - — - — - — - — - — - — - — - — - — - — - — - — - — - — - — - — - — - -

void __fastcall TForm1::Bt_aquanetskClick(TObject *Sender)
{
std::auto_ptr<TStringList>content(new TStringList());

content->LoadFromFile(ExtractFilePath(Application->ExeName) + "aquanetsk.txt");

char *prh_chars = "0123456789+t";
char *prh_words[] = {"lesson", "class", "ссылка", NULL};

int cou = 0;
double sumdlt = 0;
double tbeg;

AnsiString original_content = content->Text;
int lcou0 = content->Count;

CkB_aquanetsk->Checked = false;

while (!CkB_aquanetsk->Checked)
{ tbeg = double(Now());

content->Text = Delete_Prohibited_Lines(original_content, prh_chars, prh_words);

double dltt = (double)(Now() — tbeg) * (24.*60.*60.);
cou++;
sumdlt += dltt;
Lbl_aquanetsk->Caption = AnsiString("")
+ "Всего циклов " + AnsiString(cou) + " "
+ "последний " + FormatFloat("0.00", dltt) + " s "
+ "строк до/после " + AnsiString(lcou0) + "/" + AnsiString(content->Count) + " "
+ "среднее время " + FormatFloat("0.00", sumdlt / cou) + " s "
;
Application->ProcessMessages();
}

Memo1->Lines->Add(Lbl_aquanetsk->Caption);
content->SaveToFile(ExtractFilePath(Application->ExeName) + "aquanetsk_out.txt");
}

//---------------------------------------------------------------------------

#include <string.h>

AnsiString __fastcall Delete_Prohibited_Lines
(const AnsiString &itext // вход
,const char *prh_chars // запрещенные символы
,char **prh_words // список запрещенных слов (ограничен NULL)
)
{
// буфер состояния сравнений с запрещенными словами
int prh_words_cnt;
for (prh_words_cnt = 0; true; prh_words_cnt++)
if (!prh_words[prh_words_cnt]) break;

char **prh_words_wrk = new char*[prh_words_cnt];
for (int i(0); i < prh_words_cnt; i++) prh_words_wrk[i] = prh_words[i];


char *inp = itext.c_str();
char *buf = new char[strlen(inp)+1];
char *bp  = buf;
char *cline;  // начало текущей строки
bool skip_line  = false; // флаг игнорирования текущей строки

for (cline = inp; *inp; *inp++)
{ char c = *inp;

if (c == '\n') // конец строки
 { if (!skip_line)  // в строке нет запрещенных символов
  { memcpy(bp, cline, inp — cline + 1);
  bp += inp — cline + 1;
  }
 skip_line = false;  // приведение к стартовому состоянию
 cline = inp+1;
 for (int i(0); i < prh_words_cnt; i++) prh_words_wrk[i] = prh_words[i];
 continue;
 }
else
 { if (skip_line) continue; // просто ищем конец строки
 }

if (strchr(prh_chars, c)) // это запрещенный символ?
 { skip_line = true;  // да
 continue;
 }

// ну и наконец поищем запрещенные слова
for (int i(0); i < prh_words_cnt; i++)
 { char w = *(prh_words_wrk[i])++;
 if (w != c)
  { prh_words_wrk[i] = prh_words[i];
  continue;
  }
 if (*(prh_words_wrk[i]) == 0x00)
  { skip_line = true;
  break;
  }

 }

}
if (cline < inp ) // вход не заканчивался \n — сбросить остаток буфера
{ if (!skip_line)  // в строке нет запрещенных символов
 { memcpy(bp, cline, inp — cline);
 bp += inp — cline;
 }
}

*bp = 0x00;
AnsiString ret(buf);

delete [] prh_words_wrk;
delete [] buf;
return ret;
}

//---------------------------------------------------------------------------


PS.
Обратите внимание на
char *prh_chars = "0123456789+t"; // список запрещенных символов
char *prh_words[] = {"lesson", "class", "ссылка", NULL}; // список запрещенных слов
и Delete_Prohibited_Lines(original_content, prh_chars, prh_words);


PPS. Ну почему тэги code так безбожно съедают все отсупы.
aquanet sk
  Отправлено: 22.02.2007, 22:16


Станционный диспетчер

Группа: Участник
Сообщений: 87



Оба примера хороши, спасибо большое! ( и форум кстати тоже хороший, много отзывчивых людей)
На быстродействие у себя проверю их в ближайшее время, но при виде результов примера AVC конечно настроение поднимается до почти истерического смеха, 25000, пусть и строк текста, за 2-3 секунды yahoo.gif, оочень полезное свойство (с такими темпами уже можно двигаться в сторону обработки авиационной информации, поверьте мне, там таких задач хватает с головой). Второй пример также порадовал тем, что там решена проблема с использованием функции Memo1->Lines->Strings[i].Length();, она там просто не используется, правда передо мной сейчас ещё одна задача стоит — удалять строки, в которых больше 10-ти символов, т.е. там, где длина строк больше 10 любых значащих символов, идут/находятся предложения (реклама и т.п.), которые не нужны на выходе, и строки с этими предложениями надо удалять.

Сейчас попробовал по-быстрому объединить пример AVC со следующим кодом:
CODE
int cur= Memo1->Lines->Count-1;
...
for(;cur>=0;cur--)
{
if( Memo1->Lines->Strings[cur].Length() > 10) Memo1->Lines->Delete(cur);
Application->ProcessMessages(); // эта функция кстати тоже несколько увеличивает время обработки, но для моего примера в десяток тысяч другой строк разница несущественна
}
...
Memo1->Text = Delete_Prohibited_Lines(original_content, prh_chars, prh_words);
...
Результат снова неутешительный — сотни секунд.

Теперь хотелось бы задать несколько вопросов по примеру AVC, связанных больше наверное с моими неглубокими знаниями языка, поэтому сразу извиняюсь за некорректые вопросы.

1. buf — почему к strlen приплюсовывается 1? strlen и так вроде все \n учитывает. ( я сейчас из-за позднего времени просто не могу сообразить/увидеть/осмыслить smile.gif )
*bp=0x00; — какую функциональную нагрузку несет эта строка, зачем устанавливать 0x00? (подозреваю это для оптимизации памяти)

2. memcpy(bp, cline, inp — cline + 1); — если подряд много пустых строк идет, состоящих только из \0\n, то в этом месте из-за учета + 1-ой символа \n, все они также будут копироваться, а это фактически лишнее для нас действие; насколько оно может замедлить общий процесс обработки? Не быстрее ли (в плане скорости обработки данных) будет использовать дополнительный if ?
2.1 Также по поводу оптимальности (ну и скорости обработки) смущает for (int i(0); i < prh_words_cnt; i++) prh_words_wrk[i] = prh_words[i]; в операторе if (c == '\n') // конец строки,
ведь если строка оказалась полезной ( не подходящей на удаление ), то цикл проведет свою работу в холостую. Но конечно при той свыше достаточной для моего случая скорости это уже просто чисто из интереса.

3.
CODE
// ну и наконец поищем запрещенные слова
for (int i(0); i < prh_words_cnt; i++)
{ char w = *(prh_words_wrk[i])++;
if (w != c)
{ prh_words_wrk[i] = prh_words[i];
continue;
}
if (*(prh_words_wrk[i]) == 0x00)
{ skip_line = true;
break;
}

}
как говорится, не понял целиком — этот цикл для меня оказался сложноватым, не понимаю как тут ведется сравнение с эталонными словами. При первой же итерации сразу инкремент — *(prh_words_wrk[i])++, получается сравниваем текущим символ (с) со следущим символом в prh_words_wrk, далее неразгляжу где сравнение с остальными символами эталонов, потому что на следующей итерации идет сравнение уже со вторым эталоном, т.е. берется каждый эталон, его второй символ сравнивается с текущим символом (с), потом след. эталон, и доходим до NULL: if (*(prh_words_wrk[i]) == 0x00)
ну по логике понятно, что рано или поздно мы до NULL дойдем и он конечно совпадет с 0x00, а в этом операторе стоит skip_line = true;(парадокс) , по идее он (случай при совпадении с эталоном) д.б. раньше наступить и цикл д.б. прерваться , а мы уе дошли до NULL, в общем ещё раз повторю, не судите строго, не могу понять что происходит в этом операторе — for (int i(0); i < prh_words_cnt; i++)

4. Вы использовали загрузку из файла, это меня навело на старые вопросы. Дело в том, что я копирую в Memo текст со страничек вручную. А причина в том, что я не научился обращаться к элементам странички браузеров (пробовал на Maxthon, Avant, Opera). Я могу найти их окна, нажать какую-нибудь кнопку, ввести адрес, но вот скопировать оттуда текст, а что ещё сложнее и важнее, определить состояние 100% загрузки странички (напомню, мне за раз надо несколько web-страниц обрабатывать), не получается. Желательно с Opera научиться определять 100%-ую загрузку документа/странички (работа с ней будет вестись), но там ещё этот элемент состояния загрузки динамический, "попробуй поймай его " smile.gif В общем может посоветуете функции какие-нибудь и т.п..., буду признателен за любую информацию.

Отредактировано aquanet sk — 23.02.2007, 04:44
aquanet sk
Отправлено: 23.02.2007, 03:51


Станционный диспетчер

Группа: Участник
Сообщений: 87



Всех поздравляю с 23 февраля!

Желаю побольше таких информативных тем, как эта, чтобы будущим форумчанам не пришлось бы /с удивлением на скупость интернета на информацию (в данном контексте)/ штудировать весь интернет в поиске от силы 2-3-х хороших тем по конкретным вопросам, где есть что-то полезное и поучительное. Теперь уже (по крайней мере на этом форуме), топик про обработку большого количества строк можно считать выполненным — есть 2 хорошие темы.
Ну и в общем всё в таком духе, успешных поисков, удачных находок и мужества!
aquanet sk
  Отправлено: 23.02.2007, 04:34


Станционный диспетчер

Группа: Участник
Сообщений: 87



По поводу моего нулевого вопроса (про .Length() и критерий "10 значащих символов"):

Код 1
CODE
char XXsym=0;
for (cline = inp; *inp; *inp++)
{ char c = *inp; // [B]а почему Вы переменную "с" объявили именно внутри цикла? всё равно после цикла почти нет операторов и функция заканчивается[/B]
XXsym++;
if (c == '\n') // конец строки
{
if(XXsym>12)skip_line=true;
if (!skip_line) // в строке не было запрещенных символов, копируем её
...
XXsym=0;
...
}
else
{
if(XXsym>12)continue;
if (skip_line) continue; // просто ищем конец строки
}

...
if (cline < inp ) // вход не заканчивался \n — сбросить остаток буфера
{
if(XXsym>10)skip_line=true;
if (!skip_line) // в строке нет запрещенных символов
{...}
}


Код 2
CODE

else
{
if(inp — cline>10){skip_line=true; continue;} // [B]что-то про \0\n я не то наверное написал через сообщение назад, либо здесь надо > 11 ставить[B]
if (skip_line) continue; // просто ищем конец строки
}


Какой из них посоветуете (главное скорость, а в Коде 2 она ниже я думаю)? Если никакой, то может набросаете, как оптимально это можно реализовать?

Отредактировано aquanet sk — 23.02.2007, 12:29
AVC
Отправлено: 23.02.2007, 09:58


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE (aquanet sk @ 22.02.2007, 21:16)

Теперь хотелось бы задать несколько вопросов по примеру AVC,
1. buf — почему к strlen приплюсовывается 1?
*bp=0x00; — какую функциональную нагрузку несет эта строка

Это так называемые строки asciiz (ascii + zerro) — последовательность байтов с обязательным концевым 0x00. Про него надо помнить.

QUOTE (aquanet sk @ 22.02.2007, 21:16)

2. memcpy(bp, cline, inp — cline + 1); — если подряд много пустых строк идет, состоящих только из \n, то в этом месте из-за учета + 1-ой символа \n, все они также будут копироваться

Удаления пустых строк как и строк из пробелов не было в условиях задачи, решается добавлением if'ов и флагов. Если возникнут затруднения — помогу.

QUOTE (aquanet sk @ 22.02.2007, 21:16)

2.1 Также по поводу оптимальности (ну и скорости обработки) смущает for (int i(0); i < prh_words_cnt; i++) prh_words_wrk[i] = prh_words[i]; в операторе if (c == '\n') // конец строки,
ведь если строка оказалась полезной ( не подходящей на удаление ), то цикл проведет свою работу в холостую.

Согласен, ему место в блоке if (!skip_line) { }
Зачеркнуто
Нет, так делать нельзя. Условий возникновения skip_line = true много и рабочий массив может остаться в промежуточном состоянии.
for должен остаться где и был.

QUOTE (aquanet sk @ 22.02.2007, 21:16)

3.// ну и наконец поищем запрещенные слова
как говорится, не понял целиком

В рабочем массиве указатели на символ каждого слова с которым нужно сравнивать символ входа. В начале каждой строки они указывают на начало слов. Символ слова извлекается в w, указатель смещается к следующему (конструкция char = *char_pointer++). Если символ слова не совпадает с входом, рабочий указатель ставится на начало слова, если он указывает на 0x00 — достигнут конец слова, что означает присутствие данного слова в исходном потоке.

QUOTE (aquanet sk @ 22.02.2007, 21:16)

т.е. там, где длина строк больше 10 любых символов ... строки с этими предложениями надо удалять.

Вы и сами предложили решение. smile.gif
if((inp — cline)>10){skip_line=true; continue;}

QUOTE (aquanet sk @ 22.02.2007, 21:16)

4. ... я не научился обращаться к элементам странички браузеров (пробовал на Maxthon, Avant, Opera). Я могу найти их окна, нажать какую-нибудь кнопку, ввести адрес, но вот скопировать оттуда текст, а что ещё сложнее и важнее, определить состояние 100% загрузки странички ... не получается.

Лично я странички для подобной обработки предпочитаю получать прямо с сервера. Передать данные по HTTP из программы скрипту

PS.
!!! С праздником !!!
AVC
Отправлено: 23.02.2007, 13:31


Ветеран

Группа: Модератор
Сообщений: 1583



Испавлен ответ на 2.1 в предыдущем посте.
aquanet sk
  Отправлено: 28.02.2007, 00:13


Станционный диспетчер

Группа: Участник
Сообщений: 87



0. ясно
1. ясно
2. ясно
3. Здесь мне не до конца понятно, как осуществляется перебор символов в каждой анси строке. Попробую объяснить, в чем моя загвоздка:

В начале получаем значение количества запрещенных слов, включая NULL:
prh_words_cnt=5

Далее в цикле на первой итерации i=0, т.е. prh_words_wrk[i] указывает на первое слово, и если первый символ этого слова не совпал со входом, то i=1, берем первый символ УЖЕ второго слова и т.д. С такой ситуацией всё понятно.

Но если скажем на первой итерации w и c совпали, то ( ну проверили следующий символ на предмет конца строки, эт понятно) также наступает следующая итерация, i=1. И со входом сравниваем снова первый символ УЖЕ второго слова, и так пока не достигнем 5-ой итерации, после которой цикл просто завершится. В общем вот так я всё ошибочно сравниваю и высчитываю. smile.gif

4. ясно. Спасибо, поштудирую эту тему (файл уже скачал smile.gif , тут главное научиться отправлять/очищать запросы, имитируя нажатие кнопок Отправить/Сбросить web-формы. Начну с примера www.stream.ru — положить деньги на счет. Давно мечтал автоматизировать подобные операции, чтобы моя прога сама зашла в систему (авторизировалась), перешла на нужную страничку в нужный раздел, ввела в поля коды с карты оплаты ( эт для Стрима ), нажала Отправить и после отправки вышла из системы. Если получится такая програмка, создам отдельную тему потом wink.gif

Отредактировано aquanet sk — 10.03.2007, 04:11
aquanet sk
Отправлено: 10.03.2007, 03:50


Станционный диспетчер

Группа: Участник
Сообщений: 87



To beginner
QUOTE
Но в HTML-ских строках часто команды
форматирования и то что выводится на экран находятся в одной строке...

А я c html строками и не работаю. Я работаю с тем, что получается в результате их "компиляции".

Для нашего примера на одной/каждой из страничек может содержаться:

lesson one
part 1
...
part 2
...
+++ Good lessons on www.xxxxxxx.com +++ // тут типа реклама
part 14

table
task
teacher
...


Отредактировано aquanet sk — 10.03.2007, 04:08
AVC
Отправлено: 12.03.2007, 12:05


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE (aquanet sk @ 10.03.2007, 04:11)

4. ясно. Спасибо, поштудирую эту тему (файл уже скачал smile.gif , тут главное научиться отправлять/очищать запросы, имитируя нажатие кнопок Отправить/Сбросить web-формы.

Вообще-то я предлагал совершенно другое. biggrin.gif
Предлагалось не нажимать кнопочки в неком веб-бровсере а используя сокеты работать непосредственно с сервером. Ведь отправка данных через форму это не более чем http запрос, сформированный по просым и известным правилам. Если ответ прост, то для его аналазиза можно обойтись без html парсера.


QUOTE (aquanet sk @ 10.03.2007, 04:11)

3. Здесь мне не до конца понятно, как осуществляется перебор символов в каждой анси строке.

Подготовительные действия
1. Подсчет количества запрещенных слов. Входной параметр, массив произвольного размера указателей на слова, ограниченный NULL'ом в последнем элементе.
for (prh_words_cnt = 0; true; prh_words_cnt++)
if (!prh_words[prh_words_cnt]) break;
После выполнения prh_words_cnt содержит действительное кол-во слов без учета завершающего NULL

2. Так как в процессе сравнения указатели на слова (на их начала) будут портится создаю рабочий массив для хранения положений текущих стравнений.
char **prh_words_wrk = new char*[prh_words_cnt];
for (int i(0); i < prh_words_cnt; i++) prh_words_wrk[i] = prh_words[i];
В результате в массиве prh_words_wrk есть prh_words_cnt указателей, которые указыват на символ с которым должно происходить сравнение (здесь на первый символ слова)


Рабочий цикл сравнения
// ну и наконец поищем запрещенные слова
for (int i(0); i < prh_words_cnt; i++)
//для каждого из указателей рабочего массива

{ char w = *(prh_words_wrk[i])++;
// в w извлекается текущий символ текущего слова, указатель позиционируется на следующий символ этого слова

if (w != c)
{ prh_words_wrk[i] = prh_words[i];
continue;
}
// если сравниваемый символ не совпадает с символом входа
// указатель позиционируется на начало слова (взводится в исходное состояние)
// и переход к следующему слову

if (*(prh_words_wrk[i]) == 0x00)
{ skip_line = true;
break;
}
// если достигнут конец текущего слова
// эта строка входа не нужна
// и продолжение анализа бессмысленно

}
aquanet sk
Отправлено: 15.03.2007, 13:47


Станционный диспетчер

Группа: Участник
Сообщений: 87



QUOTE (AVC @ 12.03.2007, 12:05)
Вообще-то я предлагал совершенно другое. biggrin.gif

1. Значит я неправильно выразился, просто хотел пояснить, каких именно действий от сервера жду (загвоздка в слове "имитируя", имел ввиду имитируя запросы через веб-формы), а так то конечно я уже не думаю о браузерах, когда можно намного быстрее получать инфу, отправляя запросы к серверу непосредственно из моей программы.

2. ну в общем-то написано всё тоже самое, что было понятно изначально; мне кажется, я достаточно подробно описал, что именно мне для меня осталось не ясным, а именно случай, который наступает, если НЕ сработало это[CODE]if (w != c)
{ prh_words_wrk[i] = prh_words[i];
continue;
}
// если сравниваемый символ не совпадает с символом входа
// указатель позиционируется на начало слова (взводится в исходное состояние)
// и переход к следующему слову
[CODE]

и НЕ сработало это

[QUOTE]// если достигнут конец текущего слова
// эта строка входа не нужна
// и продолжение анализа бессмысленно[QUOTE]

т.е. остался не ясным [B]момент перехода в следующему символу в слове[B], поскольку итерации у нас есть только по словам, а переход по символам (занесение в w) в каждом слове происходит только при каждой новой итерации по словам. Ну не суть, ладно, главное работает.
AVC
Отправлено: 15.03.2007, 15:05


Ветеран

Группа: Модератор
Сообщений: 1583



То же самое — это естественно, код то ведь не меняется smile.gif я просто добавил комментариев.

если НЕ сработало это if (w != c)
и не сработало это if (*(prh_words_wrk[i]) == 0x00) (достигнут конец слова)
то
рабочий указатель текущего слова уже спозиционирован так что слева от него совпавшие символы, под ним символ который будет сравниваться с входным на следующей итерации.
Позиционирование происходит здесь char w = *(prh_words_wrk[i])++; операцией атоинкремента (++)
Эта строка еще подробнее (хотя куда уж дальше)
prh_words_wrk[i] — указатель на текущую позицию текущего слова
*(prh_words_wrk[i]) — символ под указателем
*(prh_words_wrk[i])++ — смещение указателя к следующему символу

Запись полностью эквивалента (типовое решение) часто встречающейся конструкции типа
char *cp = "123";
while (*cp) if (*cp++ == "2") break;
aquanet sk
Отправлено: 16.03.2007, 16:50


Станционный диспетчер

Группа: Участник
Сообщений: 87



блин, да это всё понятно smile.gif (хых, уже всё разжевали, пережевали как могли biggrin.gif )

получается мне не было ясно, почему запись char w = *(prh_words_wrk[i])++; эквивалента ...while (*cp) if..., ведь я всё никак не мог понять, где же "зарыт" второй (внутренний) цикл. Я этого синтаксиса не знал. Но теперь опыт повысился, благодаря Вам, AVC. rolleyes.gif Спасибо.
я
Отправлено: 16.03.2007, 17:51


Не зарегистрирован







Простите, но чуствую, что вы так и не поняли
QUOTE (aquanet sk @ 16.03.2007, 16:50)

получается мне не было ясно, почему запись char w = *(prh_words_wrk[i])++;  эквивалента ...while (*cp) if...,

Не так char w = *(prh_words_wrk[i])++; эквивалента *cp++

QUOTE (aquanet sk @ 16.03.2007, 16:50)

ведь я всё никак не мог понять, где же "зарыт" второй (внутренний) цикл.

Он ни где не зарыт. Его просто нет за ненадобностью biggrin.gif . Его функцию исполняет верхний фор, читающий входной поток.
aquanet sk
Отправлено: 21.03.2007, 12:52


Станционный диспетчер

Группа: Участник
Сообщений: 87



ну всё

Присоединить изображение

Присоединить изображение


Вернуться в Вопросы программирования в C++Builder