Python中使用re.MULTLINE匹配一个字符串的多行
2019-09-07 17:42:05 +08 字数:785 标签: Python有时会遇到这种类型的需求:在一个包括换行符的字符串中,匹配行首以某字符(比如+
)开头的行数。
当然,这只是一个具体化的问题,但背后有一个通用场景:如何把一个字符串当做多行来处理,并且还比较高效。
一个形如a\nb\n+c\n+d
的字符串,要想知道+
开头的行数,大概有以下几种做法。
先按行切分为列表 ¶
最差版本 ¶
>>> s = 'a\nb\n+c\n+d'
>>> lines = s.split('\n')
>>> len([x for x in lines if x.startswith('+')])
2
以上是最直观的版本,也是最差的版本。 它有许多可以优化的细节。
优化分行 ¶
lines = s.splitlines()
直接通过\n
来分行,容易出问题。
换行符一共有三种:
\n
:Unix及其衍生系统,如Linux、FreeBSD、Mac OS X。\r\n
:Dos衍生系统,主要是Windows。\r
:早期Mac OS,以及一些特殊场景。
其中,\r
是回车符号,即return
,含义是输入位置移动到行首,对应的是早期打字机把滚筒向左移动到行首的操作;
\n
是换行符,即newline
,含义是输入位置移动到下一行。
由此可见,\r\n
才是一次完整的换行操作。
而在Unix系统中,省略\r
可以减少编码,因为newline
的输入位置一定是行首,丢掉了历史包袱,现在更为流行。
但无论如何,鉴于换行符的复杂性,分行操作建议用splitlines
来实现。
改len为sum ¶
sum(1 for x in lines if x.startswith('+'))
由于这里只需要个数,而不需要内容,因此可以用sum
来实现计算,省略了生成列表的开销。
对迭代器计算次数,这种方法可以通用。
利用re.MULTLINE做多行匹配 ¶
上面的方案有个问题,就是一定要把一个字符串先分为多个小字符串列表。 这在超大字符串场景下,会出现显著的性能问题,对内存的无效占用很高。
利用正则表达式的多行匹配可以解决这个问题。
>>> s = 'a\nb\n+c\n+d'
>>> import re
>>> sum(1 for i in re.finditer(r'^\+', s, re.MULTILINE))
2
这里用到了标准库的re模块。 由于re.search只能找一个,re.find返回的是一个列表,因此这里选择了re.finditer,空间占用降低到了极致。