Ruby - 将多行制表符分隔的字符串解析为数组数组

时间:2016-03-01 01:49:11

标签: transform tab-delimited multilinestring

我很抱歉,如果已经在Ruby设置中提出这个问题 - 我在发布之前进行了检查,但是说实话,这是非常漫长的一天,如果我错过了显而易见的事情,我会提前道歉!

我有以下字符串,其中包含系统上安装的软件包列表,由于某种原因,我最难解析它。我知道必须有一个直接的方法在Ruby中这样做,但我一直在做空。

我想将下面的多行,制表符分隔的字符串解析为数组数组,然后我可以使用each_with_index遍历每个数组元素,并将HTML代码吐出到我的Rails应用程序中。

str = 'Product and/or Software Full Name 5242     [version 6.5.24]     [Installed on: 12/31/2015]

 Product and/or Software Full Name 5426     [version 22.4]     [Installed on: 06/11/2013]

 Product and/or Software Full Name 2451     [version 1.63]     [Installed on: 12/17/2015]

 Product and/or Software Full Name 5225     [version 43.22.51]     [Installed on: 11/15/2011]

 Product and/or Software Full Name 2420     [version 43.51-r2]     [Installed on: 12/31/2015]'

最终结果将是一个包含5个元素的数组数组,如下所示:

  

[["产品和/或软件全名5245"],["版本6.5.24"],   ["安装于:2015年12月31日"],["产品和/或软件全名5426"],["版本22.4"],[ "安装于:2013年6月11日"],["产品和/或软件全名2451"],["版本1.63"],[& #34;安装于:2015年12月17日"]]

请注意:为简洁起见,仅显示5个阵列中的3个

我更愿意从“版本”和“版本”中删除括号。和'安装在'但如果不能轻易地将其解释为答案,我可以单独使用gsub。

最后一件事是,不会总是安装在'多行字符串中每一行的条目,因此答案需要考虑到这一点。

1 个答案:

答案 0 :(得分:1)

这应该做:

expr = /(.+?)\s+\[([^\]]+)\](?:\s+\[([^\]]+)\])?/
str.scan(expr)

表达式实际上远不如它看起来那么复杂。它看起来很复杂,因为我们匹配必须转义的方括号,并且还使用字符类,这些字符括在正则表达式语言的方括号中。总之,它会增加很多噪音。

这里分开了:

expr = /
  (.+?)  # Capture #1: Any characters (non-greedy)

  \s+    # Whitespace
  \[     # Literal '['
    (      # Capture #2:
      [^\]]+   # One or more characters that aren't ']'
    )
  \]     # Literal ']'

  (?:    # Non-capturing group
    \s+    # Whitespace
    \[     # Literal '['
      ([^\]]+) # Capture #3 (same as #2)
    \]     # Literal ']'
  )?     # Preceding group is optional
/x

如您所见,第三部分与第二部分完全相同,只是在非捕获组中跟随?使其成为可选项。

值得注意的是,如果可能的话,这可能会失败,例如产品名称包含方括号。如果这是可能的,一个可能的解决方案是在匹配中包含versionInstalled文本,例如:

expr = /(.+?)\s+\[(version [^\]]+)\](?:\s+\[(Installed [^\]]+)\])?/

P.S。这是一个使用String#split代替的解决方案:

expr = /\]?\s+\[|\]$/
res = str.each_line.map {|ln| ln.strip.split(expr) }
        .reject {|arr| arr.empty? }

如果产品名称中包含括号,则此处可能的解决方法是指定部件之间的最小间距数,例如:

expr = /\]?\s{3,}\[|\]$/

......当然,这取决于产品名称从不超过三个连续的空格。