Python正则表达式用标点符号快速替换多个关键字,并以

2024-04-25 01:43:23 发布

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

这是这个previous question的一个扩展

我有一本python字典,是这样做的

a = {"animal": [ "dog", "cat", "dog and cat"], "XXX": ["I've been", "asp*", ":)"]}

我想找到一个解决方案,用它们的键尽可能快地替换字典值中的所有单词。解决方案对于大文本应该是可伸缩的。如果单词以星号结尾,则意味着文本中以该前缀开头的所有单词都应替换

所以下面这句话“我一直很坏,但我渴望成为一个更好的人,像我的狗和猫一样:)”应该转化为“XXX坏,但我XXX做一个更好的人,像我的动物XXX

我正在尝试使用trrex来实现这一点,认为它应该是最快的选择。它是?但是我不能成功。 此外,我发现问题:

  • 在处理包含标点符号的单词时(如“:”和“我曾经”)
  • 当一些字符串像“狗”和“狗和猫”一样重复时

您能用可扩展的解决方案帮助我实现目标吗


Tags: and文本字典ve解决方案星号单词cat
1条回答
网友
1楼 · 发布于 2024-04-25 01:43:23

您可以调整this solution以满足您的需要:

  • a创建另一个字典,该字典将包含相同的键和从值创建的正则表达式
  • 如果找到*字符,如果您指的是任何零个或多个单词字符,请将其替换为\w*;如果您指的是任何零个或多个非空白字符,请使用\S*(请调整def quote(self, char)方法),否则,请引用字符
  • 使用明确的单词边界(?<!\w)(?!\w),或者如果它们干扰匹配的非单词条目,则将它们全部删除
  • 这里的第一个正则表达式看起来像(?<!\w)(?:cat|dog(?:\ and\ cat)?)(?!\w)demo),第二个看起来像(?<!\w)(?::\)|I've\ been|asp\w*)(?!\w)demo
  • 在循环中替换

Python demo

import re

# Input
text = "I've been bad but I aspire to be a better person, and behave like my dog and cat :)"
a = {"animal": [ "dog", "cat", "dog and cat"], "XXX": ["I've been", "asp*", ":)"]}

class Trie():
    """Regex::Trie in Python. Creates a Trie out of a list of words. The trie can be exported to a Regex pattern.
    The corresponding Regex should match much faster than a simple Regex union."""
    def __init__(self):
        self.data = {}

    def add(self, word):
        ref = self.data
        for char in word:
            ref[char] = char in ref and ref[char] or {}
            ref = ref[char]
        ref[''] = 1

    def dump(self):
        return self.data

    def quote(self, char):
        if char == '*':
            return r'\w*'
        else:
            return re.escape(char)

    def _pattern(self, pData):
        data = pData
        if "" in data and len(data.keys()) == 1:
            return None

        alt = []
        cc = []
        q = 0
        for char in sorted(data.keys()):
            if isinstance(data[char], dict):
                try:
                    recurse = self._pattern(data[char])
                    alt.append(self.quote(char) + recurse)
                except:
                    cc.append(self.quote(char))
            else:
                q = 1
        cconly = not len(alt) > 0

        if len(cc) > 0:
            if len(cc) == 1:
                alt.append(cc[0])
            else:
                alt.append('[' + ''.join(cc) + ']')

        if len(alt) == 1:
            result = alt[0]
        else:
            result = "(?:" + "|".join(alt) + ")"

        if q:
            if cconly:
                result += "?"
            else:
                result = "(?:%s)?" % result
        return result

    def pattern(self):
        return self._pattern(self.dump())

# Creating patterns
a2 = {}
for k,v in a.items():
    trie = Trie()
    for w in v:
        trie.add(w)
    a2[k] = re.compile(fr"(?<!\w){trie.pattern()}(?!\w)", re.I)

for k,r in a2.items():
    text = r.sub(k, text)
    
print(text)
# => XXX bad but I XXX to be a better person, and behave like my animal XXX

相关问题 更多 >