【问题标题】:Splitting the content of brackets without separating the brackets ruby拆分括号的内容而不分离括号 ruby
【发布时间】:2015-08-08 17:37:41
【问题描述】:

我目前正在开发一个 ruby​​ 程序来计算术语。它工作得很好,除了一件事:括号。我需要过滤内容,或者至少将内容放入数组中,但我已经尝试了一个小时来提出解决方案。这是我的代码:

splitted = term.split(/\(+|\)+/)

我需要一个数组而不是括号,例如:

"1-(2+3)" #=>["1", "-", ["2", "+", "3"]]

我已经试过了:

/(\((?<=.*)\))/

但它返回了:

Invalid pattern in look-behind.

有人可以帮我解决这个问题吗?

更新

我忘了说,我的程序会拆分术语,我只需要括号的内容是一个数组。

【问题讨论】:

  • 我发现 stringscanner 更适合这类任务。
  • 无效消息似乎是因为在大多数引擎(Dot-Net 除外)中,lookbehinds 不能具有可变长度。另一件事是,如果您尝试独立解析(2+3),除非Ruby 支持递归,否则您不能这样做。而且,我不知道是不是这样。另一种方法是自己解析它,逐个字符地跟踪堆栈的嵌套。
  • 这将是一个合适的嵌套示例:(5-(3*2(4+1)-9)+7)*4

标签: ruby regex


【解决方案1】:

如果您需要使用数组跟踪括号的层次结构,您将无法仅使用正则表达式来管理它。您需要逐字解析字符串,并保留一堆表达式。

伪代码:

  • 表达式 = 新堆栈
  • 在堆栈上添加新数组
  • 字符串中的单词:
    • 如果单词是“(”:在堆栈上添加新数组
    • Else if word is ")":从堆栈中删除最后一个数组并将其添加到堆栈的(下一个)最后一个数组中
    • Else:将单词添加到堆栈的最后一个数组
  • 退出循环时,堆栈中应该只有一个数组(如果没有,则您的开/关括号不一致)。

注意:如果您的最终目标是评估表达式,您可以节省时间并在 Postfix aka Reverse-Polish Notation 中解析字符串。 也可以考虑使用off-the-shelf libraries

【讨论】:

    【解决方案2】:

    解决方案取决于您期望括号之间的模式,您没有指定。 (例如,对于"(st12uv)",您可能需要["st", "12", "uv"]["st12", "uv"]["st1", "2uv"] 等)。如果像您的示例一样,它是一个自然数,后跟一个 +,然后是另一个自然数,您可以这样做:

    str = "1-( 2+ 3)"
    
    r = /
        \(\s*  # match a left parenthesis followed by >= 0 whitespace chars
        (\d+)  # match one or more digits in a capture group
        \s*    # match >= 0 whitespace chars 
        (\+)   # match a plus sign in a capture group
        \s*    # match >= 0 whitespace chars 
        (\d+)  # match one or more digits in a capture group
        \s*    # match >= 0 whitespace chars 
        \)       # match a right parenthesis
        /x
    
    str.scan(r0).first
      => ["2", "+", "3"]
    

    假设+ 可以改为+-*/。然后你可以改变:

    (\+)
    

    到:

    ([-+*\/])
    

    请注意,在字符类中,+ 不需要转义,- 如果是该类的第一个或最后一个字符,则不需要转义(因为在这些情况下,它不会表示范围)。

    顺便说一下,您收到错误消息“Invalid pattern in look-behind”,因为 Ruby 的lookarounds 不能包含可变长度匹配(即.*)。通过积极的后向观察,您可以改用\K 来解决这个问题。例如,

    r = /
        \d+ # match one or more digits
        \K  # forget everything previously matched
        [a-z]+ # match one or more lowercase letters
        /x
    
     "123abc"[r] #=> "abc"
    

    【讨论】:

      猜你喜欢
      • 2016-05-14
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 2021-09-21
      相关资源
      最近更新 更多