应用正则表达式提取字符串
这可能是个新手问题,但怎么才能有效地用正则表达式在字符串上提取出部分内容呢?我有一个具体的解析例子来说明。
假设我有这样一个字符串:
STRING[(val1)-{val2}-!val3!]
或者
STRING[{val2}-!val3!-(val1)]
或者
STRING[!val3!-(val1)-{val2}]
等等……(所有8种组合形式的 !val3!,(val2),{val1},我就不打扰你们了)。
我可以通过一些简单的查找和分割来实现我的目的,但你会怎么做才能干净、安全地得到类似:
val1,val2,val3 = ...
的结果呢?
更新:在要解析的字符串中,val1
、val2
和 val3
是变量输入,而这三个分隔符 !! () {} 是用来帮助我知道这三个值的位置,它们各自有不同的含义。
6 个回答
1
import re
regx = re.compile('(?<=[\[-])[!({](.+?)[!)}](?=[\]-])')
for ss in ('STRING[(val1)-{val2}-!val3!]',
'STRING[{val2}-!val3!-(val1)]',
'STRING[!val3!-(val1)-{val2}]',
'STRING[!val3!-!val1!-{val2}]'):
print regx.findall(ss)
结果
['val1', 'val2', 'val3']
['val2', 'val3', 'val1']
['val3', 'val1', 'val2']
['val3', 'val1', 'val2']
但是,被利用的字符串必须严格遵循一定的格式:不能有空格,字符 !、{、} 不能在 [ 或 - 的前后出现(如果没有出现在前后,我的模式中的判断会正确处理这些情况),等等。
如果需要,正则表达式的模式可以进一步改进。
编辑
我改进了这个模式,使得如果一个值前面有 '!',它后面也必须有 '!',
如果前面有 '(', 它后面必须有 ')',
如果前面有 '{',它后面必须有 '}'。
import re
regx_1 = re.compile('(?<=[\[-])'
'[!({]'
'(.+?)'
'[!)}]'
'(?=[\]-])')
regx_2 = re.compile('(?<=[\[-])'
'(?:'
'(!)'
'|'
'(\()'
'|'
'(\{)'
')'
'(.+?)'
'(?(1)!|(?(2)\)|(?(3)\})))'
'(?=[\]\-])'
)
for ss in ('STRING[(val1)-{val2}-!val3!]',
'STRING[{val2}-!val3!-(val1)]',
'STRING[!val3!-(val1)-{val2}]',
'STRING[!val3!-!val1!-{val2}]',
'STRING[!va}-l3!-!val)-1!-{va!-)-l2}]',):
print ('------------------------------\n'
'%s\n\n%s\n\n%s\n%s\n') % (ss,
regx_1.findall(ss),
regx_2.findall(ss),
[ x[3] for x in regx_2.findall(ss)])
结果
------------------------------
STRING[(val1)-{val2}-!val3!]
['val1', 'val2', 'val3']
[('', '(', '', 'val1'), ('', '', '{', 'val2'), ('!', '', '', 'val3')]
['val1', 'val2', 'val3']
------------------------------
STRING[{val2}-!val3!-(val1)]
['val2', 'val3', 'val1']
[('', '', '{', 'val2'), ('!', '', '', 'val3'), ('', '(', '', 'val1')]
['val2', 'val3', 'val1']
------------------------------
STRING[!val3!-(val1)-{val2}]
['val3', 'val1', 'val2']
[('!', '', '', 'val3'), ('', '(', '', 'val1'), ('', '', '{', 'val2')]
['val3', 'val1', 'val2']
------------------------------
STRING[!val3!-!val1!-{val2}]
['val3', 'val1', 'val2']
[('!', '', '', 'val3'), ('!', '', '', 'val1'), ('', '', '{', 'val2')]
['val3', 'val1', 'val2']
------------------------------
STRING[!va}-l3!-!val)-1!-{va!-)-l2}]
['va', 'val', 'va']
[('!', '', '', 'va}-l3'), ('!', '', '', 'val)-1'), ('', '', '{', 'va!-)-l2')]
['va}-l3', 'val)-1', 'va!-)-l2']
1
要想得到一个完整的答案,你需要进一步说明可能的输入字符串是什么,以及要匹配的字符串格式是什么。不过,这里有一个例子,至少展示了使用 re.findall
的基本匹配机制。
>>> examples = '''STRING[(val1)-{val2}-!val3!]
... STRING[{val2}-!val3!-(val1)]
... STRING[!val3!-(val1)-{val2}]
... '''
>>> for line in examples.split('\n'):
... print re.findall(r'val\d', 'STRING[(val1)-{val2}-!val3!]')
...
['val1', 'val2', 'val3']
['val1', 'val2', 'val3']
['val1', 'val2', 'val3']
['val1', 'val2', 'val3']
编辑:这个正则表达式 r'val\d'
的意思是匹配所有由字母 val
加上一个且仅一个数字组成的部分。
希望这对你有帮助!
4
你可以使用前瞻断言和捕获组来找到任何顺序的匹配项:
import re
def matchany(subject):
match = re.match(
r"""
(?=.*\(([^()]*)\)) # Find match between () --> group 1
(?=.*\{([^{}]*)\}) # Find match between {} --> group 2
(?=.*!([^!]*)!) # Find match between !! --> group 3""",
subject, re.VERBOSE)
return match.groups() if match else None
然后你可以这样做
>>> matchany("STRING[(val1)-{val2}-!val3!]")
('val1', 'val2', 'val3')
>>> matchany("STRING[!val3!-(val1)-{val2}]")
('val1', 'val2', 'val3')
>>> matchany("STRING[(val1)-{val2}-!val3]")
>>>