我有一个损坏的csv文件,我试图读入R并使用正则表达式进行修复。
它被破坏的原因是它包含一些包含逗号的字段,但不会用双引号将这些字段包装起来。所以我必须使用正则表达式来查找这些字段,并用双引号将它们包装起来。
以下是数据源的示例:
DataField1,DataField2,Price
ID1,Value1,
ID2,Value2,$500.00
ID3,Value3,$1,250.00
所以你可以看到,在第三行中,Price字段包含一个逗号,但它没有用双引号括起来。这打破了read.table函数。
我的方法是使用readLines和str_replace_all以逗号用双引号括起价格。但是我不擅长正则表达并且卡住了。
vector <- read.Lines(file)
vector_temp <- str_replace_all(vector, ",\\$[0-9]+,\\d{3}\\.\\d{2}", ",\"\\$[0-9]+,\\d{3}\\.\\d{2}\"")
我希望输出为:
DataField1,DataField2,Price
ID1,Value1,
ID2,Value2,$500.00
ID3,Value3,"$1,250.00"
使用这种格式,我可以阅读R. 感谢任何帮助!
答案 0 :(得分:3)
lines <- readLines(textConnection(object="DataField1,DataField2,Price
ID1,Value1,
ID2,Value2,$500.00
ID3,Value3,$1,250.00"))
library(stringi)
library(tidyverse)
stri_split_regex(lines, ",", n=3, simplify=TRUE) %>%
as_data_frame() %>%
docxtractr::assign_colnames(1)
## DataField1 DataField2 Price
## 1 ID1 Value1
## 2 ID2 Value2 $500.00
## 3 ID3 Value3 $1,250.00
您可以readr::write_csv()
或write.csv()
答案 1 :(得分:2)
似乎不需要stringi或stringr包中的额外工具。 gsub
似乎非常适合这一点。您只需要了解带有成对括号的捕获组(括号到Brits)以及使用double-backslash_n约定来引用替换参数中的捕获组匹配:
txt <- "DataField1,DataField2,Price, extra
ID1,Value1, ,
ID2,Value2,$500.00,
ID3,Value3,$1,250.00, o"
vector<- gsub("([$][0-9]{1,3}([,]([0-9]{3})){0,10}([.][0-9]{0,2}))" , "\"\\1\"", readLines(textConnection(txt)) )
> read.csv(text=vector)
DataField1 DataField2 Price extra
1 ID1 Value1
2 ID2 Value2 $500.00
3 ID3 Value3 $1,250.00 o
您可以在可能重复的特定数字序列(逗号数字)和可能的句点和2位数字周围加上引号。可能有更早的关于格式化为“货币”的问题。
答案 2 :(得分:2)
以下是一些解决方案:
1)read.pattern 这使用gsubfn包中的read.pattern
读取文件(假设称为sc.csv
),以便捕获组,即模式的括号部分是字段。这将读入文件并一步完成所有操作,因此不必先使用readLines
。
^(.*?),
将匹配从开始到第一个逗号的所有内容。然后(.*?),
将与下一个逗号匹配,最后(.*)$
将匹配其他所有内容。通常*
是贪婪的,即它尽可能匹配,但是它之后的问号使它不合适。我们需要指定perl=TRUE
以便它使用perl正则表达式,因为默认情况下gsubfn使用基于Henry Spencer的正则表达式解析器的tcl正则表达式,它不支持*?
。如果您希望使用字符列而不是因子,请将as.is=TRUE
参数添加到read.pattern
。
最后一行代码会从价格列中删除$
和,
字符,并将其转换为数字。 (如果您确实想要格式化,请省略此行。)
library(gsubfn)
DF <- read.pattern("sc.csv", pattern = "^(.*?),(.*?),(.*)$", perl = TRUE, header = TRUE)
DF$Price <- as.numeric(gsub("[$,]", "", DF$Price)) ##
,并提供:
> DF
DataField1 DataField2 Price
1 ID1 Value1 NA
2 ID2 Value2 500
3 ID3 Value3 1250
2)sub 这使用非常简单的正则表达式(只是一个字符匹配)而没有包。使用问题中定义的vector
,将前两个逗号替换为分号。然后可以使用sep = ";"
read.table(text = sub(",", ";", sub(",", ";", vector)), header = TRUE, sep = ";")
如果您想要数字价格,请在(1)中添加标记为##的行。