Преобразование оператора Perl Regex в Python Regex - PullRequest
1 голос
/ 25 апреля 2019

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

У меня есть следующее:

$x =~ s/([^\"])(item\s+7[^0-9a-z\"]*management(?:[^0-9a-z]{0,3}s)?\s+discussions?\s+and\s+analysis\s+of\s+(?:financial\s+conditions?\s+|results\s+of\s+operations?)(?:\s+and\s+results\s+of\s+operations?|\s+and\s+financial\s+conditions?)?)/\1#######ITEM7:\2#######/gis;

$x =~ s/([^\"])(item\s+7[^0-9a-z\"]*a[^0-9a-z\"]*(?:quantitative\s+and\s+(?:qualitative|qualification)\s+disclosures?\s+about\s+)?market\s+risk)/\1#######ITEM7A:\2#######/gis;

$x =~ s/([^\"])(item\s+8[^0-9a-z\"]*.{0,40}financial\s+statements[^\.])/\1#######ITEM8:\2#######/gis;

@X = (split /\#\#\#\#\#\#\#/, $x)

Я считаю, что s/эквивалентен python re.split, но я не уверен, что делает /gis.

Кроме того, я не уверен, что это означает:

(@M) = ($y =~ m/((?:\d+:ITEM7 \d+:\d+ )+(?:\d+:ITEM7A \d+:\d+ )*)(?:\d+:ITEM8 \d+:\d+\s*)+/g)

Я был бы очень признателенпомощь!

РЕДАКТИРОВАТЬ:

Еще один быстрый вопрос, что именно делает:

for($i = 0; $i < scalar(@X); ++$i) {
  if($X[$i] =~ m/^(ITEM(?:7|7A|8)):(.*)$/s) {
    $Z[$i] = $2; 
    $Y[$i] = $i . ':' . $1; 
  } else {   
    $Z[$i] = $X[$i]; 
    $Y[$i] = $i . ':' . length_in_words($X[$i]);  
  }
}

sub length_in_words {
  my $x = shift;
  my @k;
  return scalar(@k = $x =~ m/(\S+)/sg);
}

Ответы [ 2 ]

5 голосов
/ 25 апреля 2019

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

Практически весь основной синтаксис регулярных выражений, которыйподдерживается на обоих этих языках одинаково или достаточно близко, так что я не буду здесь перечислять, что означает [..] или \s.Для перевода требуется общая операция (операторы, функции и т. Д.) И несколько используемых флагов

  • Группа регулярных выражений использует оператор substitution , $x =~ s/pattern/repl/, посредством чего подстановки выполняются для переменной $x (и на месте).В Python это re

  • Конечные модификаторы /gis в Perl регулярное выражение означают: найти изаменить все вхождения шаблона (/g), игнорировать регистр (/i) и заставить . сопоставить что угодно (/s), включая символ новой строки.

    В python, чтобы заменить все вхождения шаблона, просто опустите count (или установите его в ноль), который был бы четвертым аргументом в re.sub ниже (между string ифлагов), в то время как для двух других есть флагов : IGNORECASE (или I) и DOTALL (или S)

В общей сложности у нас есть

import re

result = re.sub(pattern, replacement, string, flags=re.I|re.S)

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

В дополнение к ссылке perlre и perlop, связанным выше, некоторые другие полезные ресурсы для регулярного выражения Perl - это учебное пособие perlretut и краткий справочник perlreref ,


Вот первое регулярное выражение для более полного примера.Я хотел бы сначала переписать его на стороне Perl

# Opening "item", a phrase, and phrases with alternation
my $item   = qr/(item\s+7[^0-9a-z\"]*management(?:[^0-9a-z]{0,3}s)?\s+/;
my $phrase = qr/discussions?\s+and\s+analysis\s+of\s+/;
my $pa1 = qr/(?:financial\s+conditions?\s+|results\s+of\s+operations?)/;
my $pa2 = qr/(?:\s+and\s+results\s+of\s+operations?|\s+and\s+financial\s+conditions?)?)/

$x =~ s/([^\"])$item$phrase$pa1$pa2/$1#######ITEM7:$2#######/gis;

Я использовал qr для построения правильного шаблона регулярных выражений (по духу похож на объект re.compile в Python)в то время как в этом случае также подойдет обычная строка.

Я заменил устаревшие \1 и \2 на стороне замены на $1 и $2.(\1 используется в качестве обратной ссылки для работы в соответствующей стороне регулярного выражения.)

В Python с гигантским шаблоном, как указано в вопросе

patt = re.compile("...", flags=re.I|re.S)

string = patt.sub(r"\g<1>#######ITEM7:\g<2>#######/", string)

или, лучше, сначала сформируйте подшаблоны, как указано выше (многоточие указывает на то, что они должны быть заполнены)

item   = "(item\s+..."
phrase = "discussions?..."
pa1    = "(?:financial\s..."
pa2    = "(?:\s..."

patt = re.compile(item+phrase+pa1+pa2, flags=re.I|re.S)

string = patt.sub(r"\g<1>#######ITEM7:\g<2>#######/", string)

Использование re.compile ни в коем случае не является обязательным;re.sub, приведенное выше, чаще всего точно так же.Но я считаю re.compile хорошим устройством для организации кода (оставляя без внимания вопрос эффективности).

Если вы не в Python 3 (пока), вам понадобится re.compile для использования флагов.

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

Пример: (?:[^0-9a-z]{0,3}s)? работает следующим образом

  • без захвата (?: ... ) группирует вещи (но не сохраняет их), так что это можно сделать

  • опционально с (?: ... )? с последним ? (соответствует 0 или 1 раз, в целом)

  • класс отрицанных символов [^0-9a-z] соответствует чему-либо, кроме цифры или строчной буквы ...

  • от нуля до трех раз с [^0-9a-z]{0,3} (но не нужно 0 как {3}означает то же самое)

  • s в конце является просто буквенным символом s

Обратите внимание, что с флагом /i (re.I) приведенный выше класс отрицанных символов исключает все буквы.


Последний оператор с регулярным выражением

my @M =  $y =~ m/(...)+/g;

соответствует всем вхождениям (/g) данного шаблона в строке $y (оператор совпадения m// связан с $y оператором =~ ) и возвращает список совпадений, присвоенный массиву @M.

В Perl оператор совпадения может вернуть 1 или пустую строку (true / false) или список с фактическими совпадениями, в зависимости от того, в каком context он находится. Здесь контекст списка навязывается ему тем фактом, что выражение $y =~ m/.../ присваивает массиву .

Я удалил ненужные скобки выше и добавил объявлениепеременной, my @M.Я не вижу ничего интересного в этом длинном паттерне, поэтому я оставляю это в стороне.

Вы получаете это в Python при базовом использовании re.findall


Редактирование вопроса. Код

for($i = 0; $i < scalar(@X); ++$i)

перебирает индексы массива @X, но гораздо приятнее (и лучше) это

for my $i (0..$#X)

с использованием синтаксиса $#X для последнего индекса @X и диапазонаоператор n .. m.Синтаксис $X[$i] предназначен для элемента массива @X с индексом $i.Массивы в Perl основаны на 0.

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

if ( $X[$i] =~ m/^(ITEM(?:7|7A|8)):(.*)$/s )

, где оператор совпадения m// здесь возвращает 1 /'' (true / false), находясь в скалярном контексте (условие оператора if в конечном счете требует логического значения).Поэтому, если есть совпадения, if получает ненулевое число и оценивается как true, в противном случае код падает до else.

Модификатор /s, также встречающийся в регулярных выражениях подстановки, заставляет . также соответствовать символам новой строки, чтобы весь шаблон мог совпадать между строками в многострочной строке.

В обоих if - else устанавливаются элементы ветвей других массивов (@Z и @Y), и, если было совпадение, используются шаблоны, захваченные регулярным выражением ($1 и $2).

Наконец, . является оператором конкатенации, и выражение $i . ':' . $1 объединяет значение $i, литерал : и (первый захват) $1.length_in_words() является подпрограммой.


Редактировать: подпрограмма length_in_words() добавлена ​​в вопрос.

Короче говоря: подпрограмма занимаетстрока и возвращает количество слов в ней.

Сдвиг удаляет первый элемент из массива.По умолчанию это делается для @_ (когда он находится в подпрограмме), массива с аргументами функции.Таким образом, $x является входной строкой, с которой была вызвана функция.

Регулярное выражение сопоставляет все слова (\S+ в модификаторе /g) в $x и возвращает тот список, который назначенв массив @k.Затем scalar принимает количество элементов в массиве, что возвращается.

0 голосов
/ 25 апреля 2019

Имхо, движок регулярных выражений фактически такой же, как и полученный из Python PCRE Различия в результатах связаны с использованием / заменой

s///g замена глобальных вхождений, будет re.sub () s/// "для # раз re.sub () с указанным # но re.sub () возвращает новую строку, не изменяет ее аргумент, как в perl a =~ s///

с параметром i без учета регистра будет re.IGNORECASE или re.I
s однострочный т.е. вся строка обрабатывается как один пробел за раз
- Я признаю, я понятия не имею, что это будет в Python

(@M) = ($y =~ m/((?:\d+:ITEM7 \d+:\d+ )+(?:\d+:ITEM7A \d+:\d+ )*)(?:\d+:ITEM8 \d+:\d+\s*)+/g)

Имхо это просто

@ arr = $ y = ~ / ((?: \ D +: ITEM7 \ d +: \ d +) + (?: \ D +: ITEM7A \ d +: \ d +) ) (?: \ D +: ITEM8 \ d +: \ d + \ s * * одна тысяча двадцать-одна) + / г

инструктирует Perl:
сопоставьте шаблон с любой переменной y и поместите все последующие результаты в arr array
с @arr [0] назначена первая захваченная группа, @arr [1] вторая и т. д., и последнее - это полное совпадение без прикосновения к чему-либо в оригинальном y var, в случае, если только 1 захваченная группа как (? :) захватить ни одного. Делайте это в глобальных случаях до конца пространства шаблона.

, но для подстановки - предположим, немного отличается от случая: $b = $y =~ s/((?:\d+:ITEM7 \d+:\d+ )+(?:\d+:ITEM7A \d+:\d+ )*)(?:\d+:ITEM8 \d+:\d+\s*)+/TEST_\1/g

сопоставьте шаблон с любой переменной y и замените последующие результаты на TEST_\1 (который \ 1 должен быть заменен 1-й группой захвата ()), перезаписав исходную переменную y, продолжайте делать такие также устанавливают его как новое пространство образца, присваивают логическое значение true или T или 1 в b var, если не удается оставить y как есть, присваивают
booelan false to b

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