如何在Ruby中从文本文件创建CSV

如何在Ruby中从文本文件创建CSV,ruby,csv,Ruby,Csv,我需要从一个文本文件创建一个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

我需要从一个文本文件创建一个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
需要“csv”
@calls=File.new(“修改的账单”、“r”)
CSV.open(“new.CSV”、“wb”、write_标题:true、,
标题:[“日期”、“时间”、“电话号码”、“城市”、“持续时间”、“费用”、“通话费用”])do | csv|
@打电话。每次都打电话|

csv我想你差不多明白了。这里有一个不使用正则表达式的简单方法:

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
string='01.02.2016 10:35:49 8998775纽约3:35 0,00 0,00'
数据=字符串。拆分(“”)
数据转换(3)
# => ["01.02.2016", "10:35:49", "8998775"]
data.pop(3)
# => ["3:35", "0,00", "0,00"]
data.join(“”)
#=>“纽约”
#把它放在一起
第一,第三,第二=data.shift(3),data.pop(3),[data.join(“”)]

csv这里有一个与您的示例相匹配的Regexp。如果没有其他线路,很难判断它是否适用于每个电话。对于未被Regexp匹配的调用,您将收到“cannotparse”警告。 如果有多个空格或制表符,可以将所有“”替换为“\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
如果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)/

csv有很多方法可以解决这个问题。以下是我过去做类似事情的方式:

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})
    的意思是“记住所有这些加上接下来的四位数字”
知道你可以解决剩下的模式

其优点是,一旦找出了模式,就需要计算出它们重复了多少次。如果源文本稍后发生变化,那么调整数字就非常简单。这就是正则表达式的强大功能,当你有重复的模式时,它们非常棒


综上所述,我不喜欢使用正则表达式,因为它们往往很脆弱,如果你不知道引擎是如何解析的,它们确实会减慢代码的速度。相反,我会使用类似的方法,使用
split
拆分字符串,然后
shift
pop
,从而导致城市的消失。

y你必须确定你每次收到的文本文件的格式是否相同。看看你文本文件的格式,我想你可以使用正则表达式将纽约的数字部分切掉,然后将其切掉以处理剩余的数据谢谢你的建议,但我应该如何在同一时间将数字分开呢互操作?非常好!你应该为操作添加最后一步,把它放在一起…
first=data.shift(3);third=data.pop(3);second=[data.join('');csv就可以了!谢谢:)哈,甚至更好:)你的正则表达式可以大大简化。看看使用
{n}
和/或重复非捕获组。当然,我可以使用\d{2}而不是\d\d,但我觉得它更可读,而且实际上更长。它只值得\d{4}。而且,我希望每个组都被捕获以直接获得一个数组。您的示例是什么样子的?如果您想挑剔,“和/或”只是“或”;)很好的解释!我喜欢我女朋友说“(?:\d{2}\”{2}”时的样子
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"]