应用正则表达式提取字符串

0 投票
6 回答
565 浏览
提问于 2025-04-17 08:12

这可能是个新手问题,但怎么才能有效地用正则表达式在字符串上提取出部分内容呢?我有一个具体的解析例子来说明。

假设我有这样一个字符串:

STRING[(val1)-{val2}-!val3!]

或者

STRING[{val2}-!val3!-(val1)]

或者

STRING[!val3!-(val1)-{val2}]

等等……(所有8种组合形式的 !val3!,(val2),{val1},我就不打扰你们了)。

我可以通过一些简单的查找和分割来实现我的目的,但你会怎么做才能干净、安全地得到类似:

val1,val2,val3 = ... 的结果呢?

更新:在要解析的字符串中,val1val2val3 是变量输入,而这三个分隔符 !! () {} 是用来帮助我知道这三个值的位置,它们各自有不同的含义。

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]")
>>>

撰写回答