【问题标题】:Using String#split Method使用 String#split 方法
【发布时间】:2018-01-01 13:10:30
【问题描述】:

默认情况下,#split 方法的工作方式如下:

"id,name,title(first_name,last_name)".split(",")

会给你以下输出:

["id", "name", "title(first_name", "last_name)"]

但我想要以下内容:

["id", "name", "title(first_name,last_name)"]

所以,我使用以下正则表达式(来自 this answer)使用 split 来获得所需的输出:

"id,name,title(first_name,last_name)".split(/,(?![^(]*\))/)

但是,当我再次使用另一个字符串时,这是我上面的实际输入,逻辑失败了。我的实际字符串是:

"id,name,title(first_name,last_name,address(street,pincode(id,code)))"

它给出以下输出:

["id", "name", "title(first_name", "last_name", "address(street", "pincode(id,code)))"]

而不是

["id", "name", "title(first_name,last_name,address(street,pincode(id,code)))"]

【问题讨论】:

  • @nemesv 谢谢。有什么办法可以在 ruby​​ 中实现同样的效果吗?有什么想法吗?
  • Spring#Split 支持正则表达式,因此您只需从链接问题中获取模式:"id,name,t­itle(first­_name,last­_name)".sp­lit(/,(?![­^(]*\))/)
  • @fidato 不要使用正则表达式。您正在尝试解析嵌套数据结构,而不是通过分隔符拆分字符串。正则表达式不适合这项工作。
  • @Toto 我们已经确定这不是该问题的重复。它已经作为它的副本关闭并重新打开,它包含那里提供的解决方案,并特别显示了它不起作用的情况。

标签: ruby-on-rails ruby string split


【解决方案1】:

更新答案

由于之前的答案没有像 cmets 中正确指出的那样处理所有情况,我正在用另一个解决方案更新答案。

这种方法使用分隔符| 分隔有效逗号,然后使用String#split 分隔字符串。

class TokenArrayParser
  SPLIT_CHAR = '|'.freeze

  def initialize(str)
    @str = str
  end

  def parse
    separate_on_valid_comma.split(SPLIT_CHAR)
  end

  private

  def separate_on_valid_comma
    dup = @str.dup
    paren_count = 0
    dup.length.times do |idx|
      case dup[idx]
      when '(' then  paren_count += 1
      when ')' then paren_count -= 1
      when ',' then dup[idx] = SPLIT_CHAR if paren_count.zero?
      end
    end

    dup
  end
end

%w(
  id,name,title(first_name,last_name)
  id,name,title(first_name,last_name,address(street,pincode(id,code)))
  first_name,last_name,address(street,pincode(id,code)),city(name)
  a,b(c(d),e,f)
  id,name,title(first_name,last_name),pub(name,address)
).each {|str| puts TokenArrayParser.new(str).parse.inspect }

# =>
# ["id", "name", "title(first_name,last_name)"]
# ["id", "name", "title(first_name,last_name,address(street,pincode(id,code)))"]
# ["first_name", "last_name", "address(street,pincode(id,code))", "city(name)"]
# ["a", "b(c(d),e,f)"]
# ["id", "name", "title(first_name,last_name)", "pub(name,address)"]

我确信这可以进一步优化。

【讨论】:

  • 感谢您的回答,但它也没有给我想要的结果。我想关注 o/p: ["id", "name", "title(first_name,last_name,address(street,pincode(id,code)))"]
  • 您的代码给了我 5 个字符串的数组,而我只需要 3 个字符串,即 idnametitle(first_name,last_name,address(street,pincode(id,code))‌​
  • @fidato,对此感到抱歉。已编辑。你现在可以检查吗?
  • 这是一个非常不明智的实现,取决于最好避免的feature of Ruby。它要求在同一个标​​记中遇到每个右括号。
  • 用我认为可以解决问题和 cmets 中提到的所有这些情况的另一种方法更新了我的答案。
【解决方案2】:
def doit(str)
  split_here = 0.chr
  stack = 0
  s = str.gsub(/./) do |c|
    ret = c
    case c
    when '('
      stack += 1
    when ','
      ret = split_here, if stack.zero?
    when ')'
      raise(RuntimeError, "parens are unbalanced") if stack.zero?
      stack -= 1
    end
    ret
  end
  raise(RuntimeError, "parens are unbalanced, stack at end=#{stack}") if stack > 0
  s.split(split_here)
end

doit "id,name,title(first_name,last_name)"
  #=> ["id", "name", "title(first_name,last_name)"]
doit "id,name,title(first_name,last_name,address(street,pincode(id,code)))"
  #=> ["id", "name", "title(first_name,last_name,address(street,pincode(id,code)))"]
doit "a,b(c(d),e,f)"
  #=> ["a", "b(c(d),e,f)"]
doit "id,name,title(first_name,last_name),pub(name,address)"
  #=> ["id", "name", "title(first_name,last_name)", "pub(name,address​)"]
doit "a,b(c)d),e,f)"
  #=> RuntimeError: parens are unbalanced
doit "a,b(c(d),e),f("
  #=> RuntimeError: parens are unbalanced, stack at end=["("]

当且仅当遇到逗号时stack 为零时,才会拆分逗号。如果要对其进行拆分,则将其更改为不在字符串中的字符(split_here)。 (我用0.chr)。然后在split_here 上拆分字符串。

【讨论】:

  • 我的答案最初将stack 定义为一个数组。我将'{' 推到stack when '('' 遇到'{' 时弹出一个'}'。在查看@hallucinations 的修订答案后,我意识到它只是我使用的stack 的大小,所以我简化了我的答案,使 stack 成为局部变量。
  • 我从@hallucination 修改后的答案中学到了一些东西,这让我做了进一步的编辑。我已经用特殊字符替换了不被分割的逗号,在剩余的逗号上分割,然后用逗号替换了特殊字符。用特殊字符替换要拆分的逗号更有意义,这是幻觉所做的,避免了我最后一步的需要。
【解决方案3】:

这可能是一种方法:

"id,name,title(first_name,last_name)".split(",")[0..1] << "id,name,title(first_name,last_name)".split(",")[-2..-1].join

创建一个重复的字符串并将它们拆分,然后将第一个字符串的前两个元素与第二个字符串副本的最后两个元素结合起来。至少在这种特定情况下,它会给你想要的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    • 2013-05-11
    • 2021-11-22
    • 2014-09-06
    • 2015-05-27
    相关资源
    最近更新 更多