[英]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
來拆開繩子,然后shift
並pop
導致城市被遺棄。
這是一個與你的例子相符的正則表達式。 沒有其他線路,很難判斷它是否適用於每次通話。 對於無法與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.