比如说,我想知道模式“\ section”是否在文本“abcd \ sectiondefghi”中。当然,我可以这样做:
import re
motif = r"\\section"
txt = r"abcd\sectiondefghi"
pattern = re.compile(motif)
print pattern.findall(txt)
那会给我我想要的东西。但是,每次我想在新文本中找到新模式时,我都必须更改令人痛苦的代码。因此,我想写一些更灵活的东西,比如这个(test.py
):
import re
import sys
motif = sys.argv[1]
txt = sys.argv[2]
pattern = re.compile(motif)
print pattern.findall(txt)
然后,我想在终端中运行它:
python test.py \\section abcd\sectiondefghi
然而,这不起作用(我讨厌使用\\\\section
)。
那么,有没有办法将我的用户输入(从终端或从文件)转换为python原始字符串?或者有更好的方法从用户输入进行正则表达式模式编译吗?
非常感谢。
答案 0 :(得分:27)
使用re.escape()
确保输入文本在正则表达式中被视为文字文本:
pattern = re.compile(re.escape(motif))
演示:
>>> import re
>>> motif = r"\section"
>>> txt = r"abcd\sectiondefghi"
>>> pattern = re.compile(re.escape(motif))
>>> txt = r"abcd\sectiondefghi"
>>> print pattern.findall(txt)
['\\section']
re.escape()
逃脱了所有非字母数字;在每个这样的字符前添加一个反斜杠:
>>> re.escape(motif)
'\\\\section'
>>> re.escape('\n [hello world!]')
'\\\n\\ \\[hello\\ world\\!\\]'
答案 1 :(得分:2)
执行此操作的一种方法是使用参数解析器,例如optparse
或argparse
。
您的代码看起来像这样:
import re
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-s", "--string", dest="string",
help="The string to parse")
parser.add_option("-r", "--regexp", dest="regexp",
help="The regular expression")
parser.add_option("-a", "--action", dest="action", default='findall',
help="The action to perform with the regexp")
(options, args) = parser.parse_args()
print getattr(re, options.action)(re.escape(options.regexp), options.string)
我使用它的一个例子:
> code.py -s "this is a string" -r "this is a (\S+)"
['string']
使用您的示例:
> code.py -s "abcd\sectiondefghi" -r "\section"
['\\section']
# remember, this is a python list containing a string, the extra \ is okay.
答案 2 :(得分:2)
所以,要清楚,你搜索的东西(在你的例子中是“\ section”)应该是正则表达式还是文字字符串?如果是后者,re
模块实际上不是该任务的正确工具;给定搜索字符串needle
和目标字符串haystack
,您可以执行以下操作:
# is it in there
needle in haystack
# how many copies are there
n = haystack.count(needle)
python test.py \\section abcd\sectiondefghi
# where is it
ix = haystack.find(needle)
所有这些都比基于正则表达式的版本更有效。
如果你需要在运行时将一个文字片段插入一个更大的正则表达式, re.escape
仍然有用,但是如果你最终做re.compile(re.escape(needle))
,那么在大多数情况下,这个任务都有更好的工具。 / p>
编辑:我开始怀疑这里真正的问题是shell的转义规则,它与Python或原始字符串无关。也就是说,如果你输入:
python test.py \\section abcd\sectiondefghi
进入Unix风格的shell,在Python看到它之前,shell将“\ section”部分转换为“\ section”。解决这个问题的最简单方法是告诉shell跳过unescaping,你可以把参数放在单引号中去做:
python test.py '\\section' 'abcd\sectiondefghi'
比较和对比:
$ python -c "import sys; print ','.join(sys.argv)" test.py \\section abcd\sectiondefghi
-c,test.py,\section,abcdsectiondefghi
$ python -c "import sys; print ','.join(sys.argv)" test.py '\\section' 'abcd\sectiondefghi'
-c,test.py,\\section,abcd\sectiondefghi
(在此处明确使用连接字符串上的print以避免repr
添加更多混淆...)