perl6 Регулярные выражения и названное регулярное выражение НАМНОГО медленнее, чем явное регулярное выражение;как сделать их одинаково быстрыми? - PullRequest
0 голосов
/ 09 февраля 2019

У меня есть файл данных с 1608240 строками.Файл находится в разделах.Каждый раздел имеет уникальное слово в начале строки, все разделы имеют одно и то же слово doneSection в последней строке раздела.

Я пытаюсь найти некоторые разделы, выполнив следующие действия (код переформатирован @raiph из оригинальное сообщение , чтобы сделать код легче интерпретировать):

# using named subrules/regex is EXTREMELY slow;
# it reads about 2 lines per second, and grinds to halt
# after about 500 lines: (>> is the right word boundary)
perl6 -e 'my regex a { [ <{<iron copper carbon>.join("||")}> ] };
          my $x = 0;
          for "/tmp/DataRaw".IO.lines {
            $*ERR.print( "$x 1608240 \r" );
            ++$x;
            .say if m/:i beginSection \s+ <a> >>/ or
                    (m/:i \s+ <a> \s+ /
                     ff
                     m/:i doneSection/);
          }'

# however, if I explicitly write out the regex instead of using a subrule,
# it reads about 1000 lines per second, and it gets the job done:
perl6 -e 'my $x = 0;
          for "/tmp/DataRaw".IO.lines {
            $*ERR.print( "$x 1608240 \r" );
            ++$x;
            .say if m/:i beginSection \s+
                         [ iron || copper || carbon ] >>/ or
                    (m/:i \s+
                         [ iron || copper || carbon ] \s+ /
                     ff
                     m/:i doneSection/);
          }'

Мой вопрос заключается в том, как сделать subrule настолько быстрым, как явное регулярное выражение, или, по крайней мере, не прекратить работу?Я предпочитаю использовать более высокий уровень абстракции.Это проблема с памятью двигателя регулярных выражений?Я также пытался использовать:

my $a=rx/ [ <{ < iron copper carbon > .join("||") }> ] /

, и это одинаково медленно.

Я не могу опубликовать 1,6 миллиона строк моего файла данных, но вы, вероятно, можете создать аналогичный файл для целей тестирования.

Спасибо за любые подсказки.

1 Ответ

0 голосов
/ 09 февраля 2019

Проблема не в использовании подправил / регулярных выражений имен.Это то, что внутри регулярное выражение.Это:

[ <{<iron copper carbon>.join("||")}> ]

против

[ iron || copper || carbon ]

Следующее должно устранить разницу в скорости.Пожалуйста, попробуйте и прокомментируйте свои результаты:

my regex a { || < iron copper carbon > }

Обратите внимание на первые пробелы в < iron copper ..., а не <iron copper ...>.Последнее означает подправило с именем iron с аргументами copper и т. Д. Первое означает литерал списка "кавычек", равный , как это происходит в основном языке (хотя начальный пробел необязателен в главномязык). 1

Список соответствий можно поместить в переменную массива:

my @matchers = < iron copper carbon >;
my regex a { || @matchers }

Соответствующие элементы в @matchers могут быть произвольными регулярными выражениями, а не просто строками:

my @matchers = / i..n /, / cop+er /, / carbon /;
my regex a { || @matchers }

Предупреждение: Вышесказанное работает, но при написании этого ответа я столкнулся и теперь столкнулся с проблемой, что @ символ будет интерполировать массив не возвращается .

как сделать subrule столь же быстрым, как и явное регулярное выражение

Дело не в том, что это явно.Речь идет о регулярном выражении , которое включает оценку во время выполнения.

Как правило, регулярные выражения P6 пишутся на своем собственном языке регулярных выражений 1 , который компилируется при компиляции-time по умолчанию.

Но язык регулярных выражений P6 включает возможность ввода кода, который затем оценивается во время выполнения (при условии, что это не опасно). 2

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

(Возможно также, что у вас есть некоторые плохие алгоритмы Big O Производительность происходила в связи с использованием вами оценки во время выполнения. Если это так, она становится даже хуже, чем просто интерполяция во время выполнения, потому что тогда это проблема Big O. Я не потрудился проанализировать это, потому что лучше всего использовать полностью скомпилированныйрегулярные выражения в соответствии с моим кодом выше.)

Я также пытался использовать:

my $a=rx/ [ <{ < iron copper carbon > .join("||") }> ] /

Это все еще не избегает интерполяции во время выполнения.Эта конструкция:

<{ ...  }>

интерполирует, оценивая код внутри фигурных скобок во время выполнения и затем вставляя его во внешнее регулярное выражение.

Сноски

1 «Язык» P6 на самом деле представляет собой переплетенную коллекцию DSL .

2 Если вы явно не напишите use MONKEY-SEE-NO-EVAL; (или просто use MONKEY;) pragma для того, чтобы взять на себя ответственность за инъекционные атаки, интерполяция регулярного выражения, содержащего введенные строки, ограничена во время компиляции, чтобы гарантировать, что инъекционные атаки невозможны, и P6 откажется запускать код, если он есть.Код, который вы написали, не подвержен атакам, поэтому компилятор позволил вам написать его, как вы это сделали, и скомпилировал код без суеты.

...