Ruby:使用数组列表以选择特定的列

时间:2018-07-12 15:35:40

标签: ruby

我是Ruby的新手。 在此脚本中,我想在第10行中使用选择器,而不是使用fields [0]等。 我该怎么办?

例如,数据是嵌入的。 如果我在打开或写入文件或其他任何我喜欢学习的过程中做错了,请毫不犹豫地纠正我。

#!/usr/bin/ruby

filename = "/tmp/log.csv"

selector = [0, 3, 5, 7]

out = File.open(filename + ".rb.txt", "w")
DATA.each_line do |line|
        fields = line.split("|")
        columns = fields[0], fields[3], fields[5], fields[7]
        puts columns.join("|")
        out.puts(columns.join("|"))
end
out.close


__END__
20180704150930|rtsp|645645643|30193|211|KLM|KLM00SD624817.ts|172.30.16.34|127299264|VERB|01780000|21103|277|server01|OK
20180704150931|api|456456546|30130|234|VC3|VC300179201139.ts|172.30.16.138|192271838|VERB|05540000|23404|414|server01|OK
20180704150931|api|465456786|30154|443|BAD|BAD004416550.ts|172.30.16.50|280212202|VERB|04740000|44301|18|server01|OK
20180704150931|api|5437863735|30157|383|VSS|VSS0011062009.ts|172.30.16.66|312727922|VERB|05700000|38303|381|server01|OK
20180704150931|api|3453432|30215|223|VAE|VAE00TF548197.ts|172.30.16.74|114127126|VERB|05060000|22305|35|server01|OK
20180704150931|api|312121|30044|487|BOV|BOVVAE00549424.ts|172.30.16.58|69139448|VERB|05300000|48708|131|server01|OK
20180704150931|rtsp|453432123|30127|203|GZD|GZD0900032066.ts|172.30.16.58|83164150|VERB|05460000|20303|793|server01|OK
20180704150932|api|12345348|30154|465|TYH|TYH0011224259.ts|172.30.16.50|279556843|VERB|04900000|46503|241|server01|OK
20180704150932|api|4343212312|30154|326|VAE|VAE00TF548637.ts|172.30.16.3|28966797|VERB|04740000|32601|969|server01|OK
20180704150932|api|312175665|64530|305|TTT|TTT000000011852.ts|172.30.16.98|47868183|VERB|04740000|30501|275|server01|OK

2 个答案:

答案 0 :(得分:4)

您可以使用Ruby's splat operator(搜索“ splat”)和Array.values_at来获得特定索引处的fields,如下所示:

columns = fields.values_at(*selector)

一些编码风格建议:

1。您可能希望将selector设为常量,因为不太可能希望在代码库中对其进行进一步的突变

2。outout.close并附加到DATA都可以压缩成CSV.open

CSV.open(filenname, 'wb') do |csv|
  columns.map do |col|
    csv << col
  end
end

您还可以将自定义分隔符(在您的情况下为管道|)设置为noted in this answer,如下所示:

...
  CSV.open(filenname, 'wb', {col_sep: '|') do |csv|
...

答案 1 :(得分:2)

让我们从一个更易于管理的示例开始。首先请注意,如果字符串由变量n保留,则字符串的每一行都包含相同数量(14)的竖线(#define CHECK_BIT(value, position) ((value) & (1 << position)) )。让我们将其减少到data的前4行,每行紧接在第6个竖线之前终止:

'|'

我们还需要(任意)修改data

str = data.each_line.map { |line| line.split("|").first(6).join("|") }.first(4).join("\n")
puts str
20180704150930|rtsp|645645643|30193|211|KLM
20180704150931|api|456456546|30130|234|VC3
20180704150931|api|465456786|30154|443|BAD
20180704150931|api|5437863735|30157|383|VSS

现在要回答问题。

不需要将字符串分成几行,在垂直条上分割每一行,从结果数组中选择感兴趣的元素,将其与垂直条连接起来,然后最后用换行符( whew!)。相反,只需使用String#gsub从字符串中删除所有不需要的字符即可。

selector

最后,我们将selector = [0, 3, 4] 写入文件:

terms_per_row = str.each_line.first.count('|') + 1
  #=> 6
r = /
    (?:^|\|)  # match the beginning of a line or a vertical bar in a non-capture group
    [^|\n|]+  # match one or more characters other than a vertical bar or newline
    /x        # free-spacing regex definition mode

line_idx = -1
new_str = str.gsub(r) do |s|
  line_idx += 1
  selector.include?(line_idx % terms_per_row) ? s : ''
end
puts new_str
20180704150930|30193|211
20180704150931|30130|234
20180704150931|30154|443
20180704150931|30157|383