26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
1

с++11. Сильно тормозят регулярные выражения

29.11.2012, 20:37. Показов 3845. Ответов 19
Метки нет (Все метки)

Добрый день!

Есть файл "словарь.txt", нужно прочитать его построчно и вывести в файл "результат.txt" только те строки, которые удовлетворяют регулярному выражению. Пишу:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "stdafx.h"
#include <fstream>
#include <sstream>
#include <istream>
#include <iostream>
#include <regex>
 
using namespace std;
 
int _tmain(int argc, _TCHAR* argv[])
{
    string line;
    regex re1("^[а-я]{3}$", std::regex::optimize);
 
    ifstream infile("c:\\!\\словарь.txt");
    ofstream outfile("c:\\!\\результат.txt");
 
    ofstream program3data;
    for( std::string line; getline(infile, line ); )
    {
        if (regex_match(line, re1))
        {
            outfile << line + "\n";
        }
    }
 
    infile.close();
    outfile.close();
 
    return 0;
}
Маленький файл в мегабайт обрабатывает секунд 10-15! На Perl аналогичный скрипт отрабатывает за долю секунды. В чем может быть проблема, где код тормозит?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.11.2012, 20:37
Ответы с готовыми решениями:

С++ и регулярные выражения
С++ и регулярные выражения - возможно ли ето? Какие есть библиотеки или что-то в етом роде?

Регулярные выражения
Может кто нибудь подсказать реализацию регулярных выражений на С/С++?

Регулярные выражения с++
Пользователь должен ввести строки: фамилию(первая буква должна быть заглавной), дату рождения(по...

Регулярные выражения с++11
Просветите, пожалуйста, как из следующей строки &quot;123&lt;tag&gt;456&lt;/tag&gt;789&lt;tag&gt;987&lt;/tag&gt;654321&quot; с...

19
В астрале
Эксперт С++
8048 / 4805 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
29.11.2012, 21:22 2
Suppir, boost::regex попробуйте, вполне возможно что стандартные регексы еще не оптимизированы. А так регекс в С++ вообще не быстрая штука, если что.
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 12:57  [ТС] 3
Мне кажется, медленно работают не только регулярные выражения, но и вот это место: getline(infile, line ).
0
Higher
1953 / 1219 / 120
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
30.11.2012, 15:15 4
Цитата Сообщение от Suppir Посмотреть сообщение
Мне кажется, медленно работают не только регулярные выражения, но и вот это место: getline(infile, line ).
Это вряд ли. А каким компилятором вы пользуетесь? Возможно, вы не включаете оптимизации.
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 16:40  [ТС] 5
Цитата Сообщение от diagon Посмотреть сообщение
Это вряд ли. А каким компилятором вы пользуетесь? Возможно, вы не включаете оптимизации.
Пользуюсь Visual Studio 2012 for Desktop (бесплатная версия).
0
574 / 557 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
30.11.2012, 16:59 6
Suppir, компилите в релизе или дебаге?
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 22:15  [ТС] 7
В релизе немного побыстрей, но все равно медленней, чем Perl на порядок.
0
574 / 557 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
30.11.2012, 22:20 8
Suppir, поищите на верхней панели инструментов слово Debug. и поменяйте его на релиз
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 22:22  [ТС] 9
Скорость программки на с++ получилась как у медленных скриптовых языков: Ruby или AutoIt.
0
574 / 557 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
30.11.2012, 22:24 10
Suppir, суть скрипта на перле такая же? там тоже построчное считывание? или сразу весь файл считывается?
0
Higher
1953 / 1219 / 120
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
30.11.2012, 22:25 11
Регексы - достаточная новая штуковина в стандартном с++, к тому же вы используете далеко не лучший компилятор, поэтому ничего удивительного тут нету.
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 22:30  [ТС] 12
Цитата Сообщение от I.M. Посмотреть сообщение
Suppir, суть скрипта на перле такая же? там тоже построчное считывание? или сразу весь файл считывается?
Да, тоже построчно! Аналогичный скрипт на Perl:

Perl
1
2
3
4
5
open(IN, "c:\!ловарь.txt");
open(OU, ">c:\!езультат.txt");
while(<IN>){
    print OU if /^[а-я]{3}$/
}
Он работает на порядок быстрее (в 10 - 15 раз).
0
Форумчанин
Эксперт CЭксперт С++
8194 / 5044 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.11.2012, 22:33 13
Вы в С++ считываете построчно, вот, считывает весь текст с файла в строку:
C++
1
2
3
4
5
6
7
8
9
10
std::ifstream ifstext("text.txt");
if (!ifstext)
{
    std::cerr<< "No file\n";
    return 1;
}
std::string text;
ifstext >> std::noskipws; // clears the scipws flag for the str stream
std::copy(std::istream_iterator<char>(ifstext), std::istream_iterator<char>(), 
       std::back_inserter(text) );
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 22:34  [ТС] 14
Цитата Сообщение от diagon Посмотреть сообщение
Регексы - достаточная новая штуковина в стандартном с++, к тому же вы используете далеко не лучший компилятор, поэтому ничего удивительного тут нету.
Но Perl же написан на том же си/с++, к тому же является интерпретатором (т.о. он должен быть медленней, чем скомпилированная программа).
Кстати, я пишу еще на c# около года. Так вот, на c# (.NET Framework 2.0) после всевозможных ухищрений удалось добиться скорости (в области обработки текста) в 2 раза меньше, чем у Perl. Я надеялся, что с++ пошустрее будет.
0
Higher
1953 / 1219 / 120
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
30.11.2012, 22:36 15
Кстати, есть такой бенчмарк.
Как видно из него бусторегексы более чем в 3 раза уступают по скорости гугловой либе(кстати, на первом месте тоже детище гугла), но все же почти в 2 раза быстрее перловых.
Это я к тому, что стоит использовать нормальные либы для регексов.
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 22:36  [ТС] 16
Цитата Сообщение от MrGluck Посмотреть сообщение
Вы в С++ считываете построчно, вот, считывает весь текст с файла в строку:
C++
1
2
3
4
5
6
7
8
9
10
std::ifstream ifstext("text.txt");
if (!ifstext)
{
    std::cerr<< "No file\n";
    return 1;
}
std::string text;
ifstext >> std::noskipws; // clears the scipws flag for the str stream
std::copy(std::istream_iterator<char>(ifstext), std::istream_iterator<char>(), 
       std::back_inserter(text) );
А как мне теперь пробежаться по каждой строке? Нужно ж еще разсплитить этот файл в массив.
0
Форумчанин
Эксперт CЭксперт С++
8194 / 5044 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.11.2012, 22:36 17
Кстати, реализация регексов на VS может отличаться от реализации на gcc. Можно MinGW попробовать посмотреть, мб шустрее будет.

И да, буст регекс наверняка лучше реализован.
0
26 / 26 / 11
Регистрация: 08.08.2011
Сообщений: 1,172
30.11.2012, 23:04  [ТС] 18
Цитата Сообщение от diagon Посмотреть сообщение
Кстати, есть такой бенчмарк.
Как видно из него бусторегексы более чем в 3 раза уступают по скорости гугловой либе(кстати, на первом месте тоже детище гугла), но все же почти в 2 раза быстрее перловых.
Это я к тому, что стоит использовать нормальные либы для регексов.
Гуглолиба, вроде, имеет стандарт, аналогичный POSIX, т.е. не поддерживает обратных ссылок. А они жизненно необходимы для обработки текста (поиска-замен).

Добавлено через 5 минут
Еще пару слов насчет регулярных выражений в с#.
Они сделаны по стандарту Perl, но очень неудобны. Дело в том, что Perl автоматически компилирует (оптимизирует) регулярное выражение, которое не имеет интерполируемых переменных. Если регулярка встречается в цикле, то Perl компилирует его один раз (а не каждый раз, как пытается сделать c#). В с# приходится сначала создавать регулярку с флагом "компилировать", а только потом ее использовать. Причем, создавать регулярки приходится вне цикла, где идет обработка текста. Таким образом получается, что регулярки у вас определены в одной части экрана, а применяются в другой. Это очень неудобно.

Добавлено через 6 минут
"Таким образом получается, что регулярки у вас определены в одной части экрана, а применяются в другой. Это очень неудобно."

Собственно, как и в программе, которую я привел в сабже.

Добавлено через 11 минут
Кстати, насчет бенчарка. Там сразу видно несколько критичных ошибок в коде Perl. Например, в регулярных выражения используется альтернация квантифицируемых символов (конструкции вроде /a+|b*/). При этом регулярка будет нещадно тормозить. Это общая проблема регулярок на недетерминированных конечных автоматах. Хуже только двойные квантификаторы /([a-z]*)+/ - тогда время поиска вообще взлетает по экспоненте. Нужно альтернацию убирать в код: /a+/ || /b*/. Так будет реально на порядок быстрее. Код для бенчмарка писал человек, который Perl вчера увидел.
0
382 / 280 / 31
Регистрация: 04.09.2009
Сообщений: 1,225
26.11.2013, 21:35 19
Цитата Сообщение от MrGluck Посмотреть сообщение
Вы в С++ считываете построчно, вот, считывает весь текст с файла в строку:
А поСимвольное считыавание должно быть быстрее?
0
MrGluck
26.11.2013, 22:12     с++11. Сильно тормозят регулярные выражения
  #20

Не по теме:

не прошло и года

0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.11.2013, 22:12

Регулярные выражения
Стоит задача, проверить является ли вводимая строка заданной маской. Но маска(регулярное выражение...

Регулярные выражения
Доброй ночи! Использую вот такой код void INITDIALOG(void* p){ char* bufer = new char;...

Регулярные выражения.
Здравствуйте всем! Имеется массив строк. Надо написать программу с функцией реализующей выявления...

Регулярные выражения
Здравствуйте, кто может помочь, нужно использовать регулярные выражения, чтобы при вводе...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru