仅在第一次使用多个分隔符使用正则表达式分隔

2024-06-14 10:46:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一些字符串的格式

lorem ipsum, dolor sit - amet, consectetur : adipiscing elit. Praesent vitae orc

我希望它在每个分隔符的第一个实例中被拆分,返回

['lorem ipsum',
'dolor sit', 
'amet, consectetur', 
'adipiscing elit. Praesent vitae orc']

现在我的输出是

['lorem ipsum',
'dolor sit',
'amet',
'consectetur ',
'adipiscing elit. Praesent vitae orc']

现在我使用的是re.split(', | - |: ', txt),但它将字符串中的所有实例分开。关于如何实现所需输出的任何建议

编辑:

我意识到我的问题不清楚,所以举个例子,如果字符串是

"abc: def: ijk, lmno: pqr - stu, wx"

输出应该是

["abc",
"def: ijk",
"lmno: pqr",
"stu, wxy"]

而不是

["abc",
"def",
"ijk",
"lmno",
"pqr",
"stu",
"wxy"]

Tags: 字符串defabcipsumloremdolorametsit
3条回答

您可以使用一个小类来计算替换:

import re

text = "lorem ipsum, dolor sit - amet, consectetur : adipiscing elit. Praesent vitae orc"
# text = "abc: def: ijk, lmno: pqr - stu, wx"
rx = re.compile(r'[-,:]')


class Replacer:
    def __init__(self, *args, **kwargs):
        for key in args:
            setattr(self, key, 0)
        self.needle = kwargs.get("needle")

    def __call__(self, match):
        key = match.group(0)
        setattr(self, key, getattr(self, key, 0) + 1)
        cnt = getattr(self, key, 0)
        return self.needle if cnt == 1 else key


rpl = Replacer("-", ",", ":", needle="#@#")

result = [item.strip() for item in re.split("#@#", rx.sub(rpl, text))]
print(result)

产生

['lorem ipsum', 'dolor sit', 'amet, consectetur', 'adipiscing elit. Praesent vitae orc']

如果所有分隔符必须至少出现一次,则可以使用4个捕获组,并使用3个选项中的1个(已匹配的选项除外)进行反向引用,而不是使用拆分

^(.*?)(, | - |: )(.*?)(?!\2)(, | - |: )(.*?)(?!\2|\4)(, | - |: )(.*)

图案会匹配的

  • ^字符串的开头
  • (.*?)1,尽可能少地匹配
  • (, | - |: )2,匹配列出的任何
  • (.*?)3,尽可能匹配
  • (?!\2)负前瞻,断言右侧的内容与组2中的内容不匹配(从两个有效选项中选择一个)
  • (, | - |: )4,匹配列出的任何
  • (.*?)5,尽可能匹配
  • (?!\2|\4)负前瞻,断言右侧的内容不是组2或组4中匹配的内容(选择左侧唯一有效的选项)
  • (, | - |: )6,匹配列出的任何
  • (.*)7,尽可能匹配任何字符

Regex demo

比如说

import re

regex = r"^(.*?)(, | - |: )(.*?)(?!\2)(, | - |: )(.*?)(?!\2|\4)(, | - |: )(.*)"

test_str = ("lorem ipsum, dolor sit - amet , consectetur : adipiscing elit. Praesent vitae orc\n\n"
    "abc: def: ijk, lmno: pqr - stu, wx\n\n")

matches = re.search(regex, test_str, re.MULTILINE)

if matches:
    print(matches.group(1))
    print(matches.group(3))
    print(matches.group(5))
    print(matches.group(7))

输出

lorem ipsum
dolor sit
amet , consectetur 
adipiscing elit. Praesent vitae orc

参见Python demo1demo2

值得思考的是,不确定这是否是一个有价值的答案,但可能您可以使用regex而不是re模块来利用具有非固定宽度的负向查找功能。例如:

\s*([,:-])(?<!\1.*\1)\s*

在Python中:

import regex as re
string1 = "abc: def: ijk, lmno: pqr - stu, wx"
lst1 = re.sub(r'\s*([,:-])(?<!\1.*\1)\s*', '|' , string1).split('|')
print(lst1)

结果:

['abc', 'def: ijk', 'lmno: pqr', 'stu, wx']

相关问题 更多 >