Regex, чтобы пропустить нежелательную притяжательную группу - PullRequest
0 голосов
/ 22 декабря 2018

У меня есть строка

aaaa bbbb cccc=v1

Я хочу захватить cccc = v1 (пара field_value, а не точное "cccc").Чтобы повысить производительность, я использовал атомарные группы, чтобы не тратить время на обратное отслеживание, если = не найдено

\b[^\s=]++=\w+

Но происходит то, что, несмотря на то, что он не отслеживает назад, он проверяет каждый символ в строке какследующий

aaaa bbbb cccc=v1
^
aaaa bbbb cccc=v1
 ^
aaaa bbbb cccc=v1
  ^
aaaa bbbb cccc=v1
   ^

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

aaaa bbbb cccc=v1
^
aaaa bbbb cccc=v1
     ^
aaaa bbbb cccc=v1
          ^

Я думаю, что это определенно должно улучшить производительность.

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Обновлено

Я думаю, вы найдете, что большинство разумных регулярных выражений будут достаточно эффективными при поиске пары key=value в конце строки.(Даже с длинными строками и частичными совпадениями.)

Вот некоторые моменты времени.Я использовал функцию cmpthese из этого поста для сравнения относительного времени:

import re 
import regex 

def f1():
    # re from my comment
    return re.findall(r'(?<=[ ])(\w+=\w+)$', txt, flags=re.M)

def f2():
    # the OP's regex
    return regex.findall(r'\b([^\s=]++=\w+)', txt, flags=re.M)

def f3():
    # alternate regex 
    return re.findall(r'(\w+=\w+)$', txt, flags=re.M)   

def f4():
    # CertainPerformance updated regex
    return regex.findall(r'^(?:\w+ )*+\K[^\s=]+=\w+', txt, flags=regex.M)   

def f5():
    return [line.split()[-1] for line in txt.splitlines() if re.match(r'^(\w+=\w+)$', line.split()[-1])]    

txt='''\
a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a bc d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d e=
aaaa bbbb cccc=v1
aaaa bbbb cccc
aaaa bbbb cccc=v1
'''*1000000


cmpthese([f1,f2,f3,f4,f5],c=3)  

Это печатает на Python 2 (самый медленный сверху, самый быстрый снизу):

   rate/sec    usec/pass     f2     f4     f1     f3     f5
f2        0 36721115.669     -- -27.2% -72.0% -72.0% -77.5%
f4        0 26715482.632  37.5%     -- -61.4% -61.5% -69.0%
f1        0 10300210.953 256.5% 159.4%     --  -0.0% -19.6%
f3        0 10296802.362 256.6% 159.5%   0.0%     -- -19.6%
f5        0  8280366.262 343.5% 222.6%  24.4%  24.4%     --

И Python 3:

   rate/sec    usec/pass     f2     f4     f3     f1     f5
f2        0 40880883.330     -- -42.3% -64.4% -70.3% -78.3%
f4        0 23592684.768  73.3%     -- -38.4% -48.6% -62.3%
f3        0 14544536.920 181.1%  62.2%     -- -16.6% -38.9%
f1        0 12131648.781 237.0%  94.5%  19.9%     -- -26.7%
f5        0  8888514.997 359.9% 165.4%  63.6%  36.5%     --

Я считаю, что медлительность f2 и f4 более вероятна при использовании модуля regex по сравнению с модулем re, норегулярные выражения в этих функциях требуют использования модуля regex.Регулярное выражение в f4 при сравнении яблок и яблок должно быть быстрым.

Вы можете видеть, что добавление взгляда за якорем немного увеличивает скорость по сравнению с другими с помощью модуля re,Модуль regex, скорее всего, виноват в том, что f4 медленнее других.Теоретически, это более быстрое регулярное выражение, например, в Perl.


Комментарии и «оценка эффективности» фокусируются только на количестве «шагов» в регулярном выражении 101.Это неполная картина относительной эффективности различных выражений регулярных выражений.Regex101 также имеет рейтинг ms за время, необходимое для выполнения регулярного выражения - которое зависит от серверной земли.Некоторые шаги регулярного выражения выполняются быстрее, чем другие.

Рассмотрим регулярное выражение (?<=[ ]) В regex101, в этом примере , требуется 205 шагов и ~ 2 мс на момент запуска.

Теперь рассмотрим более простое регулярное выражение из [ \t]. Для его выполнения требуется 83 шага, но те же ~ 2 мс.

Теперь рассмотрим более сложное регулярное выражение * 1053.* из (\w+)\1\b Хотя это 405 шагов, для его выполнения требуется почти в 5 раз больше времени.

Хотя steps является индикатором скорости регулярных выражений, не для каждого шага требуется одинаковое время для выполнения.Вам также нужно посмотреть общее время выполнения.

0 голосов
/ 22 декабря 2018

Одной из опций для совпадения всех символов в слове, отличном от =, будет использование (?:\w+ )* в начале шаблона.(Если слово = не гарантировано, сделайте это притяжательным, чтобы предотвратить возврат.) Затем используйте \K, чтобы забыть о ранее сопоставленном тексте, и сопоставьте слово = с [^\s=]++=\w+:

^(?:\w+ )*+\K[^\s=]+=\w+

https://regex101.com/r/RVogoh/5

Тем не менее, это только умеренное улучшение, когда вся строка для поиска мала - 63 шага, по сравнению с оригинальной

https://regex101.com/r/RVogoh/1/

, что занимает 90 шагов.Эта реализация становится значительно более эффективной, чем первоначальный посимвольный тест, только когда имеется много символов.

Обратите внимание, что \K не поддерживается в модуле re - для этого вам понадобитсяиспользовать модуль Pypi regex.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...