下了一本txt格式的小说,发现里面很多不是段落结束的地方竟然用了回车,看着很不爽,立刻祭起Python,想把里面所有的不该出现的回车消除掉。读取文件内容后,顺手写下re.sub(r'[^\n]\n[^\n]', '', content),很简单的一个正则,就是找出单个的换行符并且替换掉。用Java习惯了,因为Java的正则表达式没有lookahead等功能,我也很少时候。做完了想起python是支持lookahead的,何不试试。
先看看文档
(?=...)
Matches if ... matches next, but doesn't consume any of the string. This is called a lookahead assertion. For example, Isaac (?=Asimov) will match 'Isaac '
only if it's followed by 'Asimov'
.
就是说如果括号里的...能匹配接下来的字符串,那么就尝试匹配当前字符串,但是不消耗任何东西。这东西叫做: 前视断言。例如Isaac (?=Asimov)只有在Isaac后面跟着Asimov的时候才能匹配Isaac
我试了下
>>>re.sub(r'a(?=bc)', 'X', 'abc a')
Xbc a
果然不错,能能只能替换后面紧跟着bc的a,如果不用前视断言,那就得
>>>re.sub(r'a(bc)', r'X\1', 'abc a')
Xbc a
看到了吧,还要把bc捕获以便保留,很麻烦。
接着我就犯了个错误,我想前世断言开来就是匹配一个位置,放到我们关注的词的前后应该是无所谓的,一定要区分前后吗
>>>re.sub(r'(?=ab)c', 'X', 'abc c')
abc c
竟然不是我期望的abX c
然后才想起来,我忽略了“不消耗”三个字。前视断言的确是匹配一个位置,但这个位置只能是它之前的位置。比如
(?=bc)匹配abc中的位置:a(这里)bc,只匹配括号ab之间的位置。匹配之后,并没有消耗掉bc,下一个输入字符就是b。所以最后一个例子中,(?=ab)匹配了'abc c'的最开始,由于没有消耗ab,所以下一个输入字符是a,正则表达式期望输入的字符是c,匹配失败,(?=ab)不能匹配其他地方,整个匹配失败。
所以一定要注意:
1.lookahead所匹配的是括号里字符串的前面位置
2.没有消耗掉括号里的字符串
明白了这一种另外三种应该也没问题了
(?!...)
接下来的字符串不能和括号里的...匹配的时候,匹配当前位置。
(?<=...)
前面的字符串能和括号里的...匹配的时候,匹配当前位置。
(?<!...)
前面的字符串不能和括号里的...匹配的时候,匹配当前位置。