如何用正则表达式准确放置逗号?

How to place comma accurately with regular expression?

我是 Python 正则表达式的新手。这是我的文字:

'Condition: Remanufactured Grade: Commercial Warranty: 1 Year Parts & On-Site Labor w/Ext. Ships: Fully Assembled Processing Time: Ships from our Warehouse in 2-4 Weeks

我想使用 python 正则表达式添加逗号,结果将如下所示:

'Condition: Remanufactured ,Grade: Commercial ,Warranty: 1 Year Parts & On-Site Labor w/Ext. Ships: Fully Assembled ,Processing Time: Ships from our Warehouse in 2-4 Weeks

基本上我想定位包含冒号的单词并想从第二个字符串中添加逗号。

老实说,我不会用正则表达式来做这件事,这在很大程度上是基于你的“处理时间”示例,这让你看起来遇到了一个只能通过了解具体预期来解决的问题要解决的字符串。

代码无法神奇地知道“Processing”与“Time”的联系比与“Fully Assembled”的联系更紧密。

所以我基本上看到三种解决方案形状,我只关注第一种,因为我认为它是最好的,但我将简要总结所有三种:

  1. 使用已知字段名称的列表,这会使逗号插入变得更加困难,并仅在 comma-insertion 逻辑期间替换这些字符串。这使您的 comma-insertion 逻辑变得更简单和规则。

  2. 获取所有已知字段名称的列表,并专门查找它们以在它们前面插入逗号。这可能更糟,但如果名称列表没有改变并且预计不会改变,并且大多数名称都很棘手,那么这可能会更干净。

  3. 用现代语言建模文本预测 AI 来解决这个问题:给定一个模棱两可的字符串,例如“...:完全组装的处理时间:...”,您基本上可以用“Assembled " 并查看它对下一个标记为“处理时间”的置信度有多大,然后用“处理中”提示它并查看它对下一个标记为“时间”的置信度有多大,然后选择它更有信心的那个for 作为您的字段名称。我认为这是矫枉过正,除非您对输入的保证真的太少以至于您必须将其视为自然语言处理问题。

所以我会做选项 1,总体思路是这样的:

tricky_fields = {
    "Processing Time": "ProcessingTime",
    # add others here as needed
}
for proper_name, easier_name in tricky_fields:
    my_text = my_text.replace(f" {proper_name}: ", f" {easier_name}: ")
# do the actual comma insertions here
for proper_name, easier_name in tricky_fields:
    my_text = my_text.replace(f" {easier_name}: ", f" {proper_name}: ")

请注意,我在替换中的字段名称周围放置了空格和冒号。如果您知道您的字段总是像这样用空格和冒号分隔,那么这是更好的做法,因为它不太可能自动替换您不想替换的内容,因此以后不太可能成为错误的来源。

如果您的所有替换都不使用任何空格或冒号,那么逗号插入本身就变成了一个简单的正则表达式,因为您的目标只是 [^ :]+:,但正则表达式是一个神秘的 micro-language没有针对人类可读性进行优化,并且它不需要是正则表达式,因为您可以在 : 上拆分,然后对于该拆分的每个结果,您可以在最后一个 上拆分,然后使用 ,, 重新加入,然后重新加入整个过程:

def insert_commas(text):
    parts = text.split(":")
    new_parts = []
    for part in parts:
        most, last = part.split(" ", -1)
        new_part = " ,".join((most, last))
        new_parts.append(new_part)
    return ":".join(new_parts)

但如果您真的想使用正则表达式,这里有一个简单的正则表达式可以满足您的需求:

def insert_commas(text):
    return re.sub(' ([^ :]+: )', r' ,', text)

尽管在实际生产代码中,我会通过将两个替换分解为一个单独的可测试函数并使用某些东西 bidict 而不是常规字典来改进棘手的字段替换,如下所示:

from bidict import bidict

tricky_fields = bidict({
    "Processing Time": "ProcessingTime",
    # add others here as needed
})

def replace_fields(names, text):
    for old_name, new_name in names:
        text = text.replace(f" {old_name}: ", f" {new_name}: ")
    return text

使用 bidict 和专用函数更清晰、更 self-descriptive、更易于维护、保持一致的代码更少、更容易 test/verify,甚至获得一些运行时安全性防止意外地将两个棘手的字段名称映射到同一个替换字段。

所以将前面的两个代码块组合在一起:

text = replace_fields(tricky_fields, text)
text = insert_commas(text)
text = replace_fields(tricky_fields.inverse, text)

当然,如果您不需要进行第二次替换来撤消初始替换,您可以在逗号插入完成后将其保留as-is。无论哪种方式,这种方式都将逗号问题从造成逗号问题的棘手名称问题中分解出来 harder/complected.