在正则表达式匹配中部分替换/删除字符

时间:2016-08-23 15:07:41

标签: python regex string substitution

我试图删除字符\/<>~?`%,如果它们出现在三个&lt;&gt;内。

对于字符串:

<html><body>Multiple &lt;&lt;&lt;parameter&gt;&gt;&gt; options %to &lt;&lt;&lt;test/verify&gt;&gt;&gt; in &lt;&lt;&lt;one% g?o&gt;&gt;&gt;</body></html>

(读起来像Multiple <<<parameter>>> options %to <<<test/verify>>> in <<<one% g?o>>>。)

我想要的最后一个字符串是:

<html><body>Multiple &lt;&lt;&lt;parameter&gt;&gt;&gt; options %to &lt;&lt;&lt;testverify&gt;&gt;&gt; in &lt;&lt;&lt;one go&gt;&gt;&gt;</body></html>

请注意,'%to'中的'%'不会被删除,因为它不在&lt;&gt;的范围内。

到目前为止我尝试过这些正则表达式:

>>> s = '<html><body>Multiple &lt;&lt;&lt;parameter&gt;&gt;&gt; options %to &lt;&lt;&lt;test/verify&gt;&gt;&gt; in &lt;&lt;&lt;one% g?o&gt;&gt;&gt;</body></html>'
>>>
>>> # just getting everything between <<< and >>> is easy
... re.sub(r'((?:&lt;){3})(.*?)((?:&gt;){3})', r'\1\2\3', s)
'<html><body>Multiple &lt;&lt;&lt;parameter&gt;&gt;&gt; options %to &lt;&lt;&lt;test/verify&gt;&gt;&gt; in &lt;&lt;&lt;one%? go&gt;&gt;&gt;</body></html>'
>>> re.findall(r'((?:&lt;){3})(.*?)((?:&gt;){3})', s)
[('&lt;&lt;&lt;', 'parameter', '&gt;&gt;&gt;'),
 ('&lt;&lt;&lt;', 'test/verify', '&gt;&gt;&gt;'),
 ('&lt;&lt;&lt;', 'one%? go', '&gt;&gt;&gt;')]

但是尝试获取一系列非\/<>~?`%个字符doesn't work,因为包含它的任何内容都会被排除在外:

>>> re.findall(r'((?:&lt;){3})([^\\/<>~?`%]*?)((?:&gt;){3})', s)
[('&lt;&lt;&lt;', 'parameter', '&gt;&gt;&gt;')]
>>> re.findall(r'((?:&lt;){3})((?:[^\\/<>~?`%]*?)*?)((?:&gt;){3})', s)
[('&lt;&lt;&lt;', 'parameter', '&gt;&gt;&gt;')]
>>> re.findall(r'((?:&lt;){3})((?:[^\\/<>~?`%])*?)((?:&gt;){3})', s)
[('&lt;&lt;&lt;', 'parameter', '&gt;&gt;&gt;')]

1 个答案:

答案 0 :(得分:2)

我使用的解决方案是使用原<<<.*>>>正则表达式和re.sub的{​​{3}}选项:

>>> def illrepl(matchobj):
...     return ''.join([matchobj.group(1),
...                     matchobj.group(2).translate(None, r'\/<>~?`%'),
...                     matchobj.group(3)])
...
>>> re.sub(r'((?:&lt;){3})(.*?)((?:&gt;){3})', illrepl, s)
'<html><body>Multiple &lt;&lt;&lt;parameter&gt;&gt;&gt; options %to &lt;&lt;&lt;testverify&gt;&gt;&gt; in &lt;&lt;&lt;one go&gt;&gt;&gt;</body></html>'
>>> # verify that this is the final string I wanted:
... re.sub(r'((?:&lt;){3})(.*?)((?:&gt;){3})', illrepl, s) == '<html><body>Multiple &lt;&lt;&lt;parameter&gt;&gt;&gt; options %to &lt;&lt;&lt;testverify&gt;&gt;&gt; in &lt;&lt;&lt;one go&gt;&gt;&gt;</body></html>'
True

由于我不需要更改&lt;&gt;,我知道匹配仅适用于其中的内容,我可以使用非捕获组正则表达式的那些部分或通过使用illrepl处的完整匹配对象来删除非法/无效字符来简化group(0)函数:

>>> def illrepl(matchobj):
...     # return matchobj.group(0).translate(None, r'\/<>~?`%')  # may have unicode so can't use this
...     return re.sub(r'[\/<>~?`%]*', '', matchobj.group(0))
...
>>> re.sub(r'(?:&lt;){3}(.*?)(?:&gt;){3}', illrepl, s)
'<html><body>Multiple &lt;&lt;&lt;parameter&gt;&gt;&gt; options %to &lt;&lt;&lt;testverify&gt;&gt;&gt; in &lt;&lt;&lt;one go&gt;&gt;&gt;</body></html>'

不确定是否有办法只通过正则表达式完成此操作,而无需使用illrepl函数生成替换,并且必须在其中再次使用re.sub