簡體   English   中英

如何在Ruby中從文本文件創建CSV

[英]How to create CSV from a text file in Ruby

我需要從文本文件中創建一個CSV文件,其中包含有關我的呼叫的計費數據。 我的文本文件有如下結構:

01.02.2016 10:35:49 8998775 New York 3:35 0,00 0,00

我使用以下方法創建CSV:

require 'csv'
  @calls = File.new("modified_billing", "r")
  CSV.open("new.csv", 'wb', write_headers: true,
    headers: ["Date", "Time", "Phone number","City","Duration", "Cost", "Cost of call"]) do |csv|
    @calls.each do |call|
      csv << call.split(" ")
    end
  end

它適用於具有單一名稱的城市,但顯然它不適用於“紐約”,“拉斯維加斯”等,因為它創建了兩列。

我想你差不多了。 這是一種沒有正則表達式的簡單方法:

string = '01.02.2016 10:35:49 8998775 New York 3:35 0,00 0,00'
data = string.split(' ')

data.shift(3)
# => ["01.02.2016", "10:35:49", "8998775"]

data.pop(3)
# => ["3:35", "0,00", "0,00"]

data.join(' ')
# => "New York"

# putting it together
first, third, second = data.shift(3), data.pop(3), [data.join(' ')]
csv << first + second + third

更緊湊的東西,雖然有點難讀:

data = call.split(' ')
csv << [data.shift(3), data.pop(3)].insert(1, data.join(' ')).flatten

有很多方法可以解決這個問題。 以下是我過去做過類似事情的方式:

str = '01.02.2016 10:35:49 8998775 New York 3:35 0,00 0,00'
/(\S+) (\S+) (\d+) (.+) (\S+) (\S+) (\S+)/.match(str).captures
# => ["01.02.2016", "10:35:49", "8998775", "New York", "3:35", "0,00", "0,00"]

str = '01.02.2016 10:35:49 8998775 Chicago 3:35 0,00 0,00'
/(\S+) (\S+) (\d+) (.+) (\S+) (\S+) (\S+)/.match(str).captures
# => ["01.02.2016", "10:35:49", "8998775", "Chicago", "3:35", "0,00", "0,00"]

由於您知道字段通常以空格分隔,因此您可以使用這些字段。

如果您需要更多地驗證字段:

str = '01.02.2016 10:35:49 8998775 New York 3:35 0,00 0,00'
/([\d.]+) ([\d:]+) (\d+) (\D+?) ([\d+:]+) ([\d,]+) ([\d,]+)/.match(str).captures
# => ["01.02.2016", "10:35:49", "8998775", "New York", "3:35", "0,00", "0,00"]

str = '01.02.2016 10:35:49 8998775 Chicago 3:35 0,00 0,00'
/([\d.]+) ([\d:]+) (\d+) (\D+?) ([\d+:]+) ([\d,]+) ([\d,]+)/.match(str).captures
# => ["01.02.2016", "10:35:49", "8998775", "Chicago", "3:35", "0,00", "0,00"]

有時候我會使用更像模板的東西:

str = '01.02.2016 10:35:49 8998775 New York 3:35 0,00 0,00'
/((?:\d{2}\.){2}\d{4}) ((?:\d{2}:){2}\d{2}) (\d+) (\D+?) (\d+:\d+) ([\d,]+) ([\d,]+)/.match(str).captures
# => ["01.02.2016", "10:35:49", "8998775", "New York", "3:35", "0,00", "0,00"]

str = '01.02.2016 10:35:49 8998775 Chicago 3:35 0,00 0,00'
/((?:\d{2}\.){2}\d{4}) ((?:\d{2}:){2}\d{2}) (\d+) (\D+?) (\d+:\d+) ([\d,]+) ([\d,]+)/.match(str).captures
# => ["01.02.2016", "10:35:49", "8998775", "Chicago", "3:35", "0,00", "0,00"]

哪里:

  • \\d{2}表示“兩位數”。
  • (?:\\d{2}\\.)表示“考慮兩個數字和一個.作為一個組,但不捕獲(”記住“)它。
  • (?:\\d{2}\\.){2}表示“做兩次”。
  • ((?:\\d{2}\\.){2}\\d{4})表示“記住所有加上接下來的四位數”。

知道你可以解決剩下的模式。

優點是一旦弄清楚模式,就需要弄清楚它們重復的次數。 如果源文本稍后更改,則調整數字非常簡單。 這是正則表達式的強大功能,當你有重復的模式時它們很棒。

所有這一切,我更喜歡不使用正則表達式,因為它們往往是脆弱的,如果你不知道引擎如何解析,它們可以真正減慢你的代碼。 相反,我會選擇像Damien這樣的東西,使用split來拆開繩子,然后shiftpop導致城市被遺棄。

這是一個與你的例子相符的正則表達式。 沒有其他線路,很難判斷它是否適用於每次通話。 對於無法與Regexp匹配的調用,您將收到“無法解析”警告。 如果有多個空格或制表符,則可以將所有''替換為'\\ s +'。

if call=~/(\d\d\.\d\d\.\d\d\d\d) (\d\d:\d\d:\d\d) (\d+) (.*?) (\d+:\d\d) (\d+,\d\d) (\d+,\d\d)/ then
  csv << Regexp.last_match.captures
else
  puts "Cannot parse : #{call}"
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM