我需要将一些正则表达式从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);
}
首先,通过为那个过长的模式的组件设置变量然后在模式本身中使用它们,可以更好地编写这一切。
实际上,这两种语言支持的所有基本正则表达式语法都是相同的,或者足够接近,所以我不会在这里列出[..]
或\s
的含义。需要翻译的是整体操作(运算符,函数等)以及使用的少数标志
$x =~ s/pattern/repl/
,其中替换在变量$x
(和就地)上完成。在python中是re.sub/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
。
除了上面链接的参考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来构造一个正确的正则表达式模式(在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
获得非零数字并且评估为真,否则代码将下降到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
获取数组中的元素数量,返回的内容。
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