【问题标题】:Ruby: Using an array list in order to select specific columnsRuby:使用数组列表来选择特定的列
【发布时间】:2018-12-20 22:04:20
【问题描述】:

我是 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

【问题讨论】:

  • 这个 CSV 文件有标题吗?
  • 不,没有标题

标签: ruby


【解决方案1】:

您可以使用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|
...

【讨论】:

  • 太好了,谢谢。
【解决方案2】:

让我们从一个更易于管理的示例开始。首先请注意,如果您的字符串由变量 data 保存,则字符串的每一行都包含相同数量 (14) 的竖线 ('|')。让我们将其减少到data 的前 4 行,每行在第 6 个竖线之前立即终止:

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

我们还需要修改selector(任意):

selector = [0, 3, 4]

现在开始回答问题。

不需要将字符串分成几行,在竖条上分割每一行,从结果数组中选择感兴趣的元素,用竖条连接后者,最后用一个换行符(哇!)。相反,只需使用 String#gsub 从字符串中删除所有不需要的字符。

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

最后,我们将new_str 写入文件:

File.write(fname, new_str)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-06
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    • 2016-02-03
    • 2020-02-12
    • 2019-11-01
    • 2023-03-29
    相关资源
    最近更新 更多