字符串简单替换
有没有简单的方法可以把大多数人熟悉的简单正则表达式格式,转换成正确的Python正则表达式字符串呢?
举个例子,我需要把这个:
string = "*abc+de?"
转换成这个:
string = ".*abc.+de.?"
当然,我可以通过循环字符串,一个字符一个字符地构建另一个字符串,但这样做肯定效率不高吧?
5 个回答
1
你可能只是偶尔需要做这个替换,比如每次用户输入新的搜索字符串时,所以我觉得不需要太担心这个解决方案的效率。
你需要生成一个替换列表,用来把“用户格式”的内容转换成正则表达式。为了方便管理,我建议把这些替换存储在一个字典里,就像@Konrad Rudolph所说的那样,我会直接使用替换方法:
def wildcard_to_regex(wildcard):
replacements = {
'*': '.*',
'?': '.?',
'+': '.+',
}
regex = wildcard
for (wildcard_pattern, regex_pattern) in replacements.items():
regex = regex.replace(wildcard_pattern, regex_pattern)
return regex
注意,这个方法只适用于简单的字符替换,虽然如果需要的话,其他复杂的代码至少可以隐藏在wildcard_to_regex
这个函数里。
(另外,我不太确定?
是否应该替换成.?
-- 我觉得正常的通配符中?
表示“恰好一个字符”,所以它的替换应该是简单的.
-- 不过我还是按照你的例子来。)
2
.replacing() 方法可以快速处理通配符,但如果通配符字符串里还有其他正则表达式的特殊字符怎么办呢?比如,有人搜索 'my.thing*',可能并不是想让 '.' 匹配任何字符。在最糟糕的情况下,像是用来创建匹配组的括号可能会搞乱你最终处理正则匹配的结果。
可以使用 re.escape 来将字面字符放入正则表达式中。不过,你得先把通配符字符分开。通常的做法是用 re.split 配合一个匹配的括号,这样就能得到一个列表,格式是 [字面字符, 通配符, 字面字符, 通配符, 字面字符...]。
示例代码:
wildcards= re.compile('([?*+])')
escapewild= {'?': '.', '*': '.*', '+': '.+'}
def escapePart((parti, part)):
if parti%2==0: # even items are literals
return re.escape(part)
else: # odd items are wildcards
return escapewild[part]
def convertWildcardedToRegex(s):
parts= map(escapePart, enumerate(wildcards.split(s)))
return '^%s$' % (''.join(parts))
5
你试图转换的这些东西看起来不像正则表达式,更像是Unix系统中的通配符。Python已经有一个模块可以处理这个了。它不支持你用的“+”这种语法,但我的命令行也不支持,我觉得这种语法并不标准。
>>> import fnmatch
>>> fnmatch.fnmatch("fooabcdef", "*abcde?")
True
>>> help(fnmatch.fnmatch)
Help on function fnmatch in module fnmatch:
fnmatch(name, pat)
Test whether FILENAME matches PATTERN.
Patterns are Unix shell style:
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any char not in seq
An initial period in FILENAME is not special.
Both FILENAME and PATTERN are first case-normalized
if the operating system requires it.
If you don't want this, use fnmatchcase(FILENAME, PATTERN).
>>>