将Perl Regex语句转换为Python Regex

问题描述 投票:1回答:2

我需要将一些正则表达式从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);
}
python regex perl
2个回答
5
投票

首先,通过为那个过长的模式的组件设置变量然后在模式本身中使用它们,可以更好地编写这一切。

实际上,这两种语言支持的所有基本正则表达式语法都是相同的,或者足够接近,所以我不会在这里列出[..]\s的含义。需要翻译的是整体操作(运算符,函数等)以及使用的少数标​​志

  • 正则表达式组使用替换operator$x =~ s/pattern/repl/,其中替换在变量$x(和就地)上完成。在python中是re.sub
  • Perl正则表达式中的尾随modifiers /gis意味着:找到并替换所有出现的模式(/g),忽略大小写(/i),并使.匹配任何东西(/s),包括换行符。 在python中,要替换所有出现的模式,只需省略count(或将其设置为零),这将是下面re.sub中的第四个参数(在string和flags之间),而对于其他两个有标志: IGNORECASE (or I)DOTALL (or S)

我们一共有

import re

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

返回新字符串,与Perl的默认就地替换不同,因此如果您希望模拟给定的正则表达式,请将re.sub指定回string

除了上面链接的参考perlreperlop之外,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来构造一个正确的正则表达式模式(在Python中与re.compile对象的精神相似),而在这种情况下,一个普通的字符串也可以。

我已经用\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

请注意,使用标志/ire.I),上面的否定字符类不包括所有字母。


带正则表达式的最后一个语句

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

匹配字符串/g中给定模式的所有出现次数($y)(match operator m//$y绑定到=~ operator)并返回匹配列表,分配给数组@M

在Perl中,匹配运算符可以返回1或空字符串(true / false)或具有实际匹配的列表,具体取决于它所在的context。这里列表上下文是由表达式$y =~ m/.../ assigns to an array强加给它的。

我删除了上面不需要的括号,并添加了变量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获得非零数字并且评估为真,否则代码将下降到else

修饰符/s,也可以在替换正则表达式中看到,使得.也匹配换行符,以便整个模式可以跨多行字符串中的行匹配。

在两个if-else分支中,设置了其他数组的元素(@Z@Y),如果匹配则使用正则表达式捕获的模式($1$2)。

最后,.是连接运算符,表达式$i . ':' . $1加入$i,文字:和(第一次捕获)$1的值。 length_in_words()是一个子程序。


编辑:子程序length_in_words()现已添加到问题中。

简而言之:子例程接受一个字符串并返回其中的字数。

shift从数组中删除第一个元素。默认情况下,它对@_(在sub中时),带有函数参数的数组执行此操作。所以$x是输入字符串,该函数被调用了什么。

正则表达式匹配\S+中的所有单词(/g修饰符下的$x)并返回该列表,该列表分配给数组@k。然后scalar获取数组中的元素数量,返回的内容。


0
投票

Imho正则表达式引擎实际上与python派生的PCRE相同不同之处在于结果相关的利用/替换

s///g替换全局出现,将是re.sub()s///“for#times re.sub()with specified#但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)

Imho很简单

@arr = $ y =〜/((?:\ d +:ITEM7 \ d +:\ d +)+(?:\ d +:ITEM7A \ d +:\ d +))(?:\ d +:ITEM8 \ d +:\ d + \ \多个)+ /克

指示perl: 匹配模式对任何y变量包含并将所有后续结果放在arr数组中 @arr [0]指定了第一个捕获的组,@ alt [1]指定了第二个,依此类推,最后一个是整个匹配,没有触及原始y var中的任何内容,在这种情况下只有1个捕获的组作为(? :)没有捕获。在全局出现直到模式空间结束时进行。

但是对于替换 - 假设情况稍有不同:qazxsw poi

匹配任何$b = $y =~ s/((?:\d+:ITEM7 \d+:\d+ )+(?:\d+:ITEM7A \d+:\d+ )*)(?:\d+:ITEM8 \d+:\d+\s*)+/TEST_\1/g变量包含的模式,并用y替换后续结果(\ 1意味着用第一个捕获组()替换),覆盖到原始TEST_\1变量,继续这样做也将其设置为新的模式空间,指定booelan为true,或将T或1指定为y var,如果不成功则将b保留为原样,指定 booelan false对y

© www.soinside.com 2019 - 2024. All rights reserved.