【问题标题】:Python Regex - Fast replace of multiple keywords with punctuation and starting withPython Regex - 用标点符号快速替换多个关键字并以
【发布时间】:2021-05-07 12:27:04
【问题描述】:

这是previous question的扩展。

我有一个 python 字典,是这样制作的

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

我想找到一种解决方案,尽快用它们的键替换字典值中的所有单词。对于大文本,解决方案应该是可扩展的。如果单词以星号结尾,则表示文本中以该前缀开头的所有单词都应替换。

所以下面的句子“我一直很糟糕,但我渴望成为一个更好的人,并且表现得像我的狗和猫:)”应该变成“XXX bad but I XXX to be a better person, and doing like my animal XXX”。 p>

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

  • 处理包含标点符号的单词(例如“:)”和“I've been”);
  • 当某些字符串重复时,例如“dog”和“dog and cat”。

您能否通过可扩展的解决方案帮助我实现目标?

【问题讨论】:

    标签: python regex string replace full-text-search


    【解决方案1】:

    您可以调整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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-29
      • 1970-01-01
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 1970-01-01
      • 2011-09-14
      • 1970-01-01
      相关资源
      最近更新 更多