Skip to main content
 首页 » 编程设计

python之将Perl Regex语句转换为Python Regex

2025年05月04日14think

我需要将一些正则表达式从perl转换为python,但是我对perl regex并不熟悉。

我有以下几点:

$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); 
} 

请您参考如下方法:

首先,通过为过长的模式的组件设置变量,然后在模式本身中使用它们,可以使整个过程写得更好。

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


正则表达式组使用替换operator,$x =~ s/pattern/repl/,从而在变量$x上(以及就地)进行替换。在python中是re.sub
Perl正则表达式中的尾随modifiers /gis表示:查找并替换所有出现的模式(/g),忽略大小写(/i),并使.匹配任何内容(/s),包括新队。

在python中,要替换所有出现的模式,只需省略count(或将其设置为零),这将是下面re.sub中的第四个参数(在string和标志之间),而对于另外两个有标志:
IGNORECASE (or I)和DOTALL (or S)


我们总共有

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


它返回新字符串,这与Perl的默认就地替换不同,因此,如果要模拟给定的正则表达式,请将 re.sub分配回 string。

除了上面链接的参考 perlre和 perlop外,Perl regex的其他有用资源还有教程 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


请注意,带有标志 /i( re.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将获得非零数字并求值为true,否则代码将降为 else。

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

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

最后, .是串联运算符,表达式 $i . ':' . $1将 $i,文字 :和(第一个捕获) $1的值连接起来。 length_in_words()是一个子例程。



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

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

shift从数组中删除第一个元素。默认情况下,它将对具有函数参数的数组 @_(在子目录中)执行此操作。因此, $x是输入字符串,即使用该函数调用的内容。

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