Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > C++ Builder
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 30.12.2013, 09:06   #1
Smitt&Wesson
Старожил
 
Аватар для Smitt&Wesson
 
Регистрация: 31.05.2010
Сообщений: 13,543
Подмигивание Ненавистный - любимый AnsiString

Эта тема не вопрос. Просто хочу поделиться находкой.
В общем предыстория такая. Есть текстовый файл размером в 1 мегабайт. Он состоит из строк размером до 1000 символов (варьируется). В этих строках, есть n-е количество одинаковых подстрок от 0 до 10-и.
Задача: подсчитать все подстроки в этом файле.
Задача интересна тем, что в AnsiString есть функция нахождения первого вхождения Pos, AnsiPos, но нет функции продолжения поиска. Странно, почему разработчики этого не предусмотрели?
Первое, лобовое решение, которое пришло на ум, это удалять подстроки из строки. Очевидность неперспективности такого решения проявилась сразу. Прога "зависла" минут на 5. Связано это с тем, что проге необходимо бало сдвигать строки после удаления фрагмента.
Попробовал перебором в двух фор-циклах. Задержка оказалась не столь значительной, всего минута.
Я подумал, а нельзя-ли ещё ускорить её работу? Ведь большинство строк файла не содержит необходимой последовательности...
И вот, что у меня родилось:
Код:
// Подсчёт количества вхождений подстроки в строку
int __fastcall TForm1::CountOccurrences(const AnsiString string, const AnsiString substring)
{
int i = string.AnsiPos(substring);// Первое вхождение находим стандартным методом
if(i == 0)return 0;
i += substring.Length();// Пропускаем первое вхождение
int st=1;// так как уже есть одно вхождение
int j;
for(i; i<string.Length(); i++)
{
  j=1;// У ансистринг всё начинается не с нуля
  while(j <= substring.Length())
  {
    if(string[i] != substring[j]) goto exit;
    j++;
  }
  st++;
exit:
}
return st;
}
Программа этот файл отработала за 27 секунд. За goto прошу не костить. Пробовал с проверкой if-ом в конце цикла while. Задержка оказалась 32 секунды.
Вот такие фокусы программирования!
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder

Последний раз редактировалось Smitt&Wesson; 30.12.2013 в 19:57.
Smitt&Wesson вне форума Ответить с цитированием
Старый 30.12.2013, 15:17   #2
Rififi
Старожил
 
Регистрация: 19.08.2009
Сообщений: 2,119
По умолчанию

j=1;// У ансистринг всё начинается не с нуля

OMG. даже здесь у них сделано через (_|_) :facepalm:

решение очевидно - выкинуть нах этот отстойный AnsiString (можно и сам C++ Builder заодно) и использовать кошерный std::string
Rififi вне форума Ответить с цитированием
Старый 30.12.2013, 15:53   #3
Smitt&Wesson
Старожил
 
Аватар для Smitt&Wesson
 
Регистрация: 31.05.2010
Сообщений: 13,543
По умолчанию

Цитата:
Сообщение от Rififi Посмотреть сообщение
j=1;// У ансистринг всё начинается не с нуля

OMG. даже здесь у них сделано через (_|_) :facepalm:

решение очевидно - выкинуть нах этот отстойный AnsiString (можно и сам C++ Builder заодно) и использовать кошерный std::string
Почему сразу так. Сам по себе, это очень даже неплохой класс. У него много полезных и легко реализуемыз методов. Но вот чего авторы не додумали, так это продолжение поиска в строке. Приходится через такие костыли делать.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder
Smitt&Wesson вне форума Ответить с цитированием
Старый 30.12.2013, 16:54   #4
DpolenST
Форумчанин
 
Регистрация: 28.09.2013
Сообщений: 115
По умолчанию

чуть-чуть поправить надо
while(j <= substring.Length())

действительно быстрее, в мегабайтном тексте 70000 вхождений посчитал за 80 мс вместо 3300 мс.
Что бы еще такого сделать, чтобы ничего не делать?

Последний раз редактировалось DpolenST; 30.12.2013 в 16:57.
DpolenST вне форума Ответить с цитированием
Старый 30.12.2013, 19:52   #5
Smitt&Wesson
Старожил
 
Аватар для Smitt&Wesson
 
Регистрация: 31.05.2010
Сообщений: 13,543
По умолчанию

Цитата:
Сообщение от DpolenST Посмотреть сообщение
чуть-чуть поправить надо
while(j <= substring.Length())

действительно быстрее, в мегабайтном тексте 70000 вхождений посчитал за 80 мс вместо 3300 мс.
Да, точно. Без знака равно, он последний символ не видит. Но работала!
Код поправил.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder

Последний раз редактировалось Smitt&Wesson; 30.12.2013 в 19:55.
Smitt&Wesson вне форума Ответить с цитированием
Старый 30.12.2013, 21:32   #6
Vapaamies
Просветитель
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,844
По умолчанию

Цитата:
Сообщение от Smitt&Wesson Посмотреть сообщение
Задача интересна тем, что в AnsiString есть функция нахождения первого вхождения Pos, AnsiPos, но нет функции продолжения поиска. Странно, почему разработчики этого не предусмотрели?
А что, в этом вашем Билдере нету PosEx?
В разработке: воспроизводственный контур ИТ
Vapaamies вне форума Ответить с цитированием
Старый 30.12.2013, 21:52   #7
DpolenST
Форумчанин
 
Регистрация: 28.09.2013
Сообщений: 115
По умолчанию

еще один момент не учтен
Код:
st++;
i += substring.Length()-1;
иначе такой код
Код:
int f=CountOccurrences("111111111111","11");
выдаст 10 вместо 6-ти
Что бы еще такого сделать, чтобы ничего не делать?
DpolenST вне форума Ответить с цитированием
Старый 31.12.2013, 20:01   #8
Smitt&Wesson
Старожил
 
Аватар для Smitt&Wesson
 
Регистрация: 31.05.2010
Сообщений: 13,543
По умолчанию

Цитата:
Сообщение от Vapaamies Посмотреть сообщение
А что, в этом вашем Билдере нету PosEx?
Возможно, это недокументированная функция. Во-всяком случае, я о ней не слышал и нигде она не описана. Проверю на досуге.
Цитата:
Сообщение от DpolenST Посмотреть сообщение
еще один момент не учтен
Код:
st++;
i += substring.Length()-1;
иначе такой код
Код:
int f=CountOccurrences("111111111111","11");
выдаст 10 вместо 6-ти
Не спорю, утилитка сырая. Многие аспекты не проверялись. Проверил только то, что она работает так, как мне было нужно.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder

Последний раз редактировалось Smitt&Wesson; 31.12.2013 в 20:05.
Smitt&Wesson вне форума Ответить с цитированием
Старый 01.01.2014, 10:07   #9
Smitt&Wesson
Старожил
 
Аватар для Smitt&Wesson
 
Регистрация: 31.05.2010
Сообщений: 13,543
По умолчанию

В мой код вкралась одна недоработочка, на которую мне указал в личке один хороший человек. И он прав. Привожу исправленный код:
Код:
// Подсчёт количества вхождений подстроки в строку
int __fastcall TForm1::CountOccurrences(const AnsiString string, const AnsiString substring)
{
int i = string.AnsiPos(substring);// Первое вхождение находим стандартным методом
if(i == 0)return 0;
i += substring.Length();// Пропускаем первое вхождение
int st=1;// так как уже есть одно вхождение
int j;
for(i; i<string.Length(); i++)
{
  j=1;// У ансистринг всё начинается не с нуля
  while(j <= substring.Length())
  {
    if(string[i+j-1] != substring[j]) goto exit;
    j++;
  }
  st++;
exit:
}
return st;
}
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder

Последний раз редактировалось Smitt&Wesson; 01.01.2014 в 10:10.
Smitt&Wesson вне форума Ответить с цитированием
Старый 01.01.2014, 12:33   #10
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
Сообщение от Vapaamies Посмотреть сообщение
А что, в этом вашем Билдере нету PosEx?
в Дельфях PosEx это отдельная функция, находящаяся в модуле StrUtils(то есть отдельно от Pos), может и тут типа того?
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Любимый наш с/с++ OnixSonic C/C++ Базы данных 2 12.12.2012 15:51
Ошибка Unresolved external 'AVIA::AVIA(int, System::AnsiString, System::AnsiString, System::AnsiString, int) mexmexmex C++ Builder 3 27.12.2011 13:31
Ваш любимый ЯП Sna1L Общие вопросы по программированию, компьютерный форум 35 06.07.2011 07:48
любимый паскаль ирен Помощь студентам 0 26.12.2010 10:29
Ваш любимый смайл AngelOfDeath Свободное общение 14 04.01.2009 22:35