正则表达式仅在不成对的情况下拆分特定字符
在这个讨论串中,我找到了最快的字符串替换算法,链接在这里。我一直在尝试修改其中一个算法,以满足我的需求,特别是这个由gnibbler提供的。
我在这里再解释一下我的问题,以及我遇到的麻烦。
假设我有一个字符串,看起来像这样:
str = "The &yquick &cbrown &bfox &Yjumps over the &ulazy dog"
你会注意到字符串中有很多地方有一个“&”符号,后面跟着一个字符(比如“&y”和“&c”)。我需要把这些字符替换成我在字典中有的合适值,像这样:
dict = {"y":"\033[0;30m",
"c":"\033[0;31m",
"b":"\033[0;32m",
"Y":"\033[0;33m",
"u":"\033[0;34m"}
使用我之前讨论串中提供的gnibbler的解决方案,我现在的解决方案是:
myparts = tmp.split('&')
myparts[1:]=[dict.get(x[0],"&"+x[0])+x[1:] for x in myparts[1:]]
result = "".join(myparts)
这个方法可以正确替换字符,并且在找不到字符时不会出错。唯一的问题是,没有简单的方法可以真正在输出中保留一个“&”符号。我能想到的最简单的方法是把我的字典改成:
dict = {"y":"\033[0;30m",
"c":"\033[0;31m",
"b":"\033[0;32m",
"Y":"\033[0;33m",
"u":"\033[0;34m",
"&":"&"}
然后把我的“split”调用改成对那些后面没有其他“&”符号的“&”进行正则表达式分割。
>>> import re
>>> tmp = "&yI &creally &blove A && W &uRootbeer."
>>> tmp.split('&')
['', 'yI ', 'creally ', 'blove A ', '', ' W ', 'uRootbeer.']
>>> re.split('MyRegex', tmp)
['', 'yI ', 'creally ', 'blove A ', '&W ', 'uRootbeer.']
基本上,我需要一个正则表达式,它可以在一对中的第一个“&”符号和每个单独的“&”符号上进行分割,以便我可以通过我的字典来处理它。
如果有人有更好的解决方案,请随时告诉我。
4 个回答
可以用一个循环来查找字符串中的'&'符号,具体做法是用这个表达式:while (q = str.find('&', p)) != -1。这个循环会一直进行,直到找不到'&'符号为止。在每次找到'&'符号后,我们可以把它左边的部分(从p + 2到q - 1之间的内容)和替换的值一起添加到结果中。
re.sub可以满足你的需求。它需要一个正则表达式模式,并且可以接受一个函数来处理匹配到的内容,然后返回替换后的结果。下面的例子中,如果&后面的字符不在字典里,就不会进行替换。而&&会被替换成&,这样可以避免后面跟着字典中字符的&被误处理。
另外,'str'和'dict'这两个变量名不好,因为它们会覆盖掉Python内置的同名函数。
在下面的's'中,'& cat'不会受到影响,而'&&cat'会变成"&cat",这样就抑制了&c的翻译。
import re
s = "The &yquick &cbrown &bfox & cat &&cat &Yjumps over the &ulazy dog"
D = {"y":"\033[0;30m",
"c":"\033[0;31m",
"b":"\033[0;32m",
"Y":"\033[0;33m",
"u":"\033[0;34m",
"&":"&"}
def func(m):
return D.get(m.group(1),m.group(0))
print repr(re.sub(r'&(.)',func,s))
输出结果:
'The \x1b[0;30mquick \x1b[0;31mbrown \x1b[0;32mfox & cat &cat \x1b[0;33mjumps over the \x1b[0;34mlazy dog'
-Mark
你可以使用一种叫做“负向前瞻”的技巧(前提是你用的正则表达式引擎支持这个功能),这样就可以只匹配那些前面没有另一个“&”符号的“&”符号。
/(?<!&)&/