【问题标题】:What pattern in a grep command will match each character at most once?grep 命令中的哪种模式最多可以匹配每个字符一次?
【发布时间】:2015-07-28 22:44:14
【问题描述】:

我想仅使用给定模式中的字母在文档中查找单词,但这些字母最多只能出现一次。 假设 document.txt 由“abcd abbcd”组成 哪种模式(以及编写这种模式涉及哪些概念)将返回“abcd”而不是“abbcd”?

【问题讨论】:

  • 您需要更多示例来说明这个想法......您的示例输入中没有d
  • 哈,祝你好运。这非常不适合正则表达式。可以做到,但模式会很大。
  • @melpomene,也许你可以为这项任务推荐一个工具,或者解释为什么模式必须很大?
  • @DynoHongjun 谢谢,我修复了示例案例。

标签: regex grep


【解决方案1】:

您可以检查一个字符是否多次出现,然后否定结果(在您的源代码中):

  • 将文档拆分为单词
  • ([a-z])[a-z]*\1检查每个单词(匹配abbcd,但不匹配abcd
  • 否定结果

解释:

  • ([a-z]) 匹配任何单个字符
  • [a-z]* 允许在上面匹配的字符之后没有或更多字符
  • \1 是对在 ([a-z]) 中找到的字符的反向引用

【讨论】:

    【解决方案2】:

    这里已经有了一些好的想法,但我想提供一个用 python 实现的示例。这不一定是最佳的,但它应该可以工作。用法是:

    $ python find.py -p abcd < file.txt
    

    而find.py的实现是:

    import argparse
    import sys
    from itertools import cycle
    
    parser = argparse.ArgumentParser()
    parser.add_argument('-p', required=True)
    args = parser.parse_args()
    
    for line in sys.stdin:
        for candidate in line.split():
            present = dict(zip(args.p, cycle((0,)))) # initialize dict of letter:count
            for ch in candidate:
                if ch in present:
                    present[ch] += 1 
            if all(x <= 1 for x in present.values()):
                print(candidate)
    

    这可以满足您将模式中的每个字符最多匹配一次的要求,即它允许零匹配。如果您想将每个字符完全匹配一次,您可以将倒数第二行更改为:

            if all(x == 1 for x in present.values()):
    

    【讨论】:

      【解决方案3】:

      Melpomene 是对的,正则表达式不是解决此任务的最佳工具。正则表达式本质上是一个finite state machine。在您的情况下,当前状态可以定义为字母表中每个字母的存在标志的组合。因此,正则表达式中的内部状态总数将为 2^N,其中 N 是允许的字母数。

      定义此类正则表达式的最简单方法是列出可用字母的所有可能排列(并使用? 来消除列出较短序列的必要性)。对于三个字母 (a,b,c),正则表达式看起来像:

      a?b?c?|a?c?b?|b?a?c?|b?c?a?|c?a?b?|c?b?a?
      

      四个字母 (a,b,c,d) 变得更长:

      a?b?c?d?|a?b?d?c?|a?c?b?d?|a?c?d?b?|a?d?b?c?|a?d?c?b?|b?a?c?d?|b?a?d?c?|b?c?a?d?|b?c?d?a?|b?d?a?c?|b?d?c?a?|c?a?b?d?|c?a?d?b?|c?b?a?d?|c?b?d?a?|c?d?a?b?|c?d?b?a?|d?a?b?c?|d?a?c?b?|d?b?a?c?|d?b?c?a?|d?c?a?b?|d?c?b?a?
      

      如您所见,不是那么方便。

      没有正则表达式的解决方案取决于您的工具集。我会编写一个简单的程序,逐字处理输入文本。在单词BitSet 的开头创建,其中每个位代表所需字母表中对应字母的存在。在遍历单词时,如果与当前字母对应的位为零,则它变为一。如果出现已标记的位或字母不在字母表中,则跳过单词。如果单词被完全评估,那么它是“有效的”。

      【讨论】:

        【解决方案4】:
        grep -Pwo '[abc]+' | grep -Pv '([abc]).*\1' | awk 'length==3'
        

        地点:

        • 第一个grep:一个由模式字母组成的单词……
        • 第二个grep:...没有重复的字母...
        • awk: ...长度是字母的个数

        【讨论】:

          猜你喜欢
          • 2012-03-21
          • 1970-01-01
          • 2017-06-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多