Ruby 从字符串中删除不匹配的括号

Ruby 从字符串中删除不匹配的括号,ruby,regex,string,recursion,text-processing,Ruby,Regex,String,Recursion,Text Processing,我想从字符串中删除“未合作”括号 也就是说,所有的()都应该被删除,除非它们后面跟一个)。同样,所有)前面没有(字符串中的某个地方应该被删除 理想情况下,算法也会考虑嵌套 例如: 而不是正则表达式,也许考虑下推自动机。(我不确定Ruby正则表达式是否能处理这个问题,我相信Perl的CAN)。 一个(非常琐碎的)过程可能是: 对于输入字符串中的每个字符: 如果它不是一个“(”或“)”,那么只需将其附加到输出中即可 如果它是一个“(”号,则增加一个seen\u parens计数器并将其相加 如果它是

我想从字符串中删除“未合作”括号

也就是说,所有的
)都应该被删除,除非它们后面跟一个
。同样,所有
前面没有
字符串中的某个地方应该被删除

理想情况下,算法也会考虑嵌套

例如:


而不是正则表达式,也许考虑下推自动机。(我不确定Ruby正则表达式是否能处理这个问题,我相信Perl的CAN)。 一个(非常琐碎的)过程可能是:

对于输入字符串中的每个字符:

  • 如果它不是一个“(”或“)”,那么只需将其附加到输出中即可
  • 如果它是一个“(”号,则增加一个seen\u parens计数器并将其相加
  • 如果它是一个“'),并且所见参数>0,则添加它并减少所见参数。否则跳过它
  • 在流程结束时,如果seen_parens>0,则从流程结束时开始删除多个parens。(此步骤可以使用堆栈或递归合并到上述流程中。)

    整个过程是
    O(n)
    ,即使开销相对较高


    快乐编码。

    以下使用oniguruma。如果使用ruby1.9,oniguruma是内置的正则表达式引擎。如果使用ruby1.8,请参见此:

    更新

    我一直懒得复制和粘贴别人的正则表达式。它似乎有问题

    所以现在,我写了我自己的。我相信它现在应该起作用了

    class String
        NonParenChar = /[^\(\)]/
        def remove_unmatched_parens
            self[/
                (?:
                    (?<balanced>
                        \(
                            (?:\g<balanced>|#{NonParenChar})*
                        \)
                    )
                    |#{NonParenChar}
                )+
            /x]
        end
    end
    

    以下是我基于@pst算法的解决方案:

    class String
      def remove_unmatched_parens
        scanner = StringScanner.new(dup)
        output = ''
        paren_depth = 0
    
        while char = scanner.get_byte
          if char == "("
            paren_depth += 1
            output << char
          elsif char == ")"
            output << char and paren_depth -= 1 if paren_depth > 0
          else
            output << char
          end
        end
    
        paren_depth.times{ output.reverse!.sub!('(', '').reverse! }
        output
      end
    end
    
    类字符串
    def删除不匹配的参数
    scanner=StringScanner.new(dup)
    输出=“”
    paren_深度=0
    而char=scanner.get\u字节
    如果char==”(“
    paren_深度+=1
    
    输出构建一个简单的LR解析器:

    tokenize, token, stack = false, "", []
    
    ")(a))(()(asdf)(".each_char do |c|
      case c
      when '('
        tokenize = true
        token = c
      when ')'
        if tokenize
          token << c 
          stack << token
        end
        tokenize = false
      when /\w/
        token << c if tokenize
      end
    end
    
    result = stack.join
    
    puts result
    
    我不同意人们修改String类,因为你不应该打开一个标准类。Regex对于解析器来说非常脆弱,很难支持。我无法想象6个月后回到以前的解决方案并试图记住他们在做什么!

    算法:

  • 遍历给定的字符串
  • 进行此操作时,跟踪堆栈中的“(”位置
  • 如果找到任何“)”,请从堆栈中删除顶部元素。
    • 如果堆栈为空,请从字符串中删除“)”
  • 最后,我们可以有不匹配的大括号的位置,如果有的话
  • Java代码:
    事实上,这是全世界教学中使用的一种无法用正则表达式解析的语言的例子。现在,Ruby的
    Regexp
    比正则表达式强大得多,它们实际上可以解析这种语言,但并不完全可维护。你可以编写一个简单的使用递归下降解析器或下推自动机所需的时间甚至少于您阅读别人交给您的
    Regexp
    所需的时间,更不用说编写自己的了。如果您将
    Regexp
    拆分为多行以放入注释,可能自动机甚至会更短。感谢算法。我的答案是()你看得对吗?@pst上一个确实有问题。所以现在,我自己写了一个不同的正则表达式。这次应该没问题。希望不会爆发。所以,
    删除不匹配的父母是一个拼写错误吗?我想是的。
    
    class String
      def remove_unmatched_parens
        scanner = StringScanner.new(dup)
        output = ''
        paren_depth = 0
    
        while char = scanner.get_byte
          if char == "("
            paren_depth += 1
            output << char
          elsif char == ")"
            output << char and paren_depth -= 1 if paren_depth > 0
          else
            output << char
          end
        end
    
        paren_depth.times{ output.reverse!.sub!('(', '').reverse! }
        output
      end
    end
    
    tokenize, token, stack = false, "", []
    
    ")(a))(()(asdf)(".each_char do |c|
      case c
      when '('
        tokenize = true
        token = c
      when ')'
        if tokenize
          token << c 
          stack << token
        end
        tokenize = false
      when /\w/
        token << c if tokenize
      end
    end
    
    result = stack.join
    
    puts result
    
    wesbailey@feynman:~/code_katas> ruby test.rb
    (a)()(asdf)