繁体   English   中英

红宝石多线扫描之间; 否定?

[英]ruby multiline scan between ; and negate?

我正在尝试匹配文本;-

我用了:

  inputx.scan(/;-.+?\n[^\n]*;-/)

但它不起作用。

我的文字是:

 baseball;-1
    norm;4
   dad;3
   soda;1
  robot;-8
   mmm;3
      fly;-1
    cat;4
    bird;4
   dragon;6
  mor;-1

我需要将文本分开;-

例如,这是结果数组的第一个元素:

 baseball;-1
    norm;4
   dad;3
   soda;1
  robot;-8

这是第二个:

     fly;-1
    cat;4
    bird;4
   dragon;6
  mor;-1

您可以使用Array#split两次,第一次按行分割,第二次根据是否存在分割; ;- (使用模式/;-?/

模式/;-?/匹配分号后跟可选-

inputx.split("\n").map{|s| s.split(/;-?/)}
#=> [[" baseball", "1"], ["    norm", "4"], ["   dad", "3"], ["   soda", "1"], ["  robot", "8"], ["   mmm", "3"], ["      fly", "1"], ["    cat", "4"], ["    bird", "4"], ["   dragon", "6"], ["  mor", "1"]]

您可以使用匹配任何以-和1位或更多位数结尾的行的正则表达式,然后将任何文本匹配到以-结尾的第一行-和1位或更多位数:

/.*-\d+$(?m:.*?-\d+$)/

请参阅Rubular演示

细节

  • .*-\\d+$ - 除了换行符之外的任何0 .*-\\d+$字符,后跟-和1+位数
  • (?m:.*?-\\d+$) - 一个修饰符组. 匹配换行符匹配:
    • .*? - 任何0+字符,尽可能少
    • - - 连字符
    • \\d+ - 1位或更多位数
    • $ - 行尾。

具有scansplit模式会导致正则表达式不必要地复杂化,因为它不是问题框中的最佳工具。

我会用这样的东西:

text = <<EOT
baseball;-1
    norm;4
  dad;3
  soda;1
  robot;-8
  mmm;3
      fly;-1
    cat;4
    bird;4
  dragon;6
  mor;-1
EOT

ary = [[]]
text.lines.each do |l|
  if l[';-'] ... l[';-']
    ary.last << l
  else
    ary << []
  end
end

ary
# => [[" baseball;-1\n",
#      "    norm;4\n",
#      "   dad;3\n",
#      "   soda;1\n",
#      "  robot;-8\n"],
#     ["      fly;-1\n",
#      "    cat;4\n",
#      "    bird;4\n",
#      "   dragon;6\n",
#      "  mor;-1\n"]]

如果您不想尾随新行:

ary = [[]]
text.lines.map(&:chomp).each do |l|
  if l[';-'] ... l[';-']
    ary.last << l
  else
    ary << []
  end
end
ary
# => [[" baseball;-1", "    norm;4", "   dad;3", "   soda;1", "  robot;-8"],
#     ["      fly;-1", "    cat;4", "    bird;4", "   dragon;6", "  mor;-1"]]

如果你不想要每个元素周围的空格:

ary = [[]]
text.lines.map(&:strip).each do |l|
  if l[';-'] ... l[';-']
    ary.last << l
  else
    ary << []
  end
end
ary
# => [["baseball;-1", "norm;4", "dad;3", "soda;1", "robot;-8"],
#     ["fly;-1", "cat;4", "bird;4", "dragon;6", "mor;-1"]]

这是如何运作的? .....运算符根据它是在Range的上下文中使用还是在if条件中更改含义。 ..被称为“触发器”操作符,它在满足第一个条件时改变状态。 它将在那时开始返回true ,并将继续这样做,直到满足第二个条件,此时它再次开始返回false。 这样可以很容易地查找某些内容,然后开始对后续行进行操作,直到第二个条件发生。

通常我们会使用不同的条件,例如在文件的一行中搜索“begin”和“end”。 但在这种情况下,我们需要它不立即切换,因为开始和结束条件都是相同的,这就是...来的地方。 它在测试第二个条件之前等待一个循环,允许此代码继续,找到下一行直到“关闭” ';-' 我不得不说,这个数据集是我见过的最奇怪的数据集之一。 (最奇怪的是几年前旧电子邮件程序中的地址簿的一些二进制数据)。 我会关注产生它的过程,如果那一代在我的控制下,我会改变它以使用更标准的东西。

我们可以使用Enumerable#chunk和Ruby的触发器操作符 这不需要使用正则表达式。 str是OP给出的字符串。

arr = str.lines.chunk do |line|
  true if line.include?('-') ... line.include?('-')
end.select(&:first).map { |_,a| a.join }
  #=> ["baseball;-1\nnorm;4\ndad;3\nsoda;1\nrobot;-8\n", 
  #    "fly;-1\ncat;4\nbird;4\ndragon;6\nmor;-1\n"] 

arr.each { |s| puts "\n"; puts s }
baseball;-1
norm;4
dad;3
soda;1
robot;-8

fly;-1
cat;4
bird;4
dragon;6
mor;-1

在触发器表达中需要使用三个(不是两个)点(在上面给出的参考中搜索“三个点”)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM