使用 Regex 清理 R 中的 csv 文件
Using Regex to clean a csv file in R
这是我的第一个 post 所以我希望它足够清楚。
在我将 CSV 文件读入 R 之前,我遇到了清理 CSV 文件的问题,我花了一整天时间寻找解决方案。
我的数据应该是两列的形式。第一列是一个由 10 位数字组成的时间戳,第二列是一个由 11 或 12 个字母和数字组成的 ID(前 6 个总是数字)。
例如:
logger10 |
0821164100 | 010300033ADD
0821164523 | 010300033ADD
0821164531 | 010700EDDA0F0831102744
010700EDDA0F|
会变成:
0821164100 | 010300033ADD
0821164523 | 010300033ADD
0821164531 | 010700EDDA0F
0831102744 | 010700EDDA0F
(请原谅中间的线条,那是我试图分隔列...)。
csv 文件似乎偶尔会缺少一个逗号,这意味着有时一行会像这样结束:
0923120531,010300033ADD0925075301,010700EDD00A
我的硬件在重新启动时也会添加单词 logger10
(或任何数字记录器),这会产生类似的问题,例如logger10logger100831102744
。
我想我已经设法解决了记录器文本问题(参见代码),但我确信这可以改进。另外,我真的不想删除任何数据。
我真正的麻烦是确保在 ID 之后的正确位置有一个换行符,如果没有,我想添加一个。我以为我可以为此使用正则表达式,但我很难理解它。
如有任何帮助,我们将不胜感激!
这是我的尝试:
temp <- list.files(pattern="*.CSV") #list of each csv/logger file
for(i in temp){
#clean each csv
tmp<-readLines(i) #check each line in file
tmp<-gsub("logger([0-9]{2})","",tmp) #remove logger text
pattern <- ("[0-9]{10}\,[0-9]{6}[A-Z,0-9]{5,6}") #regex pattern ??
if (tmp!= pattern){
#I have no idea where to start here...
}
}
这里是一些原始数据:
记录器01
0729131218,020700EE1961
0729131226,020700EE1961
0831103159,0203000316DB
0831103207,0203000316DB0831103253,010700EDE28C
0831103301,010700EDE28C
0831103522,010300029815
0831103636,010300029815
0831103657,020300029815
在此处粘贴您的正则表达式 https://regex101.com/ 以查看它是否捕获所有情况。 5 或 6 个字母或数字可能会造成问题,因为当记录器错过逗号时,它可能会捕获时间戳的第一位数字。如果正则表达式捕获所有情况,则在 tmp 字符串的末尾附加一个“\n”应该可以工作。
如果您想一次完成此操作:
(?:logger\d\d )?([\dA-F]{10}),?([\dA-F]{12}) ?
可以换成
\t\n
它的作用是选择性地查找那些流氓 logger01
条目(包括它后面的 space): 组后面的尾随 ?
意味着它可以匹配 0或 1 次:如果它 确实 匹配,它会匹配。如果它不存在,比赛就会继续进行。
之后,您查找(并捕获)恰好 10 个十六进制值(数字或 A-F
)。 ,?
表示如果逗号存在,它将匹配,但它也可以匹配 0 次或 1 次(使其可选)。
之后,查找(并捕获)恰好 12 个十六进制值。最后,为了摆脱任何奇怪的尾随 space,?
(space 字符后跟 ?
)将有选择地匹配尾随 space。
您的替换将替换第一个捕获组(10 个十六进制数字),添加制表符,替换第二个捕获组(12 个十六进制数字),然后换行。
您可以在 regex101 上看到这个正在使用以查看结果。您可以使用该页面左侧的 code generator
来获取一些预格式化的 PHP/Javascript/Python,您可以将其放入脚本中。
如果您从命令行执行此操作,可以使用 perl:
perl -pe 's/(?:logger\d\d )?([\dA-F]{10}),?([\dA-F]{12}) ?/\t\n/g'
如果是其他语言,您可能需要稍微调整一下以满足您的需要。
编辑
重新阅读 OP 和评论,一个稍微更严格的正则表达式可能是
(?:logger\d\d\ )?([\dA-F]{10}),?(\d{6}[\dA-F]{5,6})\ ?
我用更改更新了 regex101 link。
这仍然会查找前 10 个十六进制值,但现在只查找 6 位数字,然后是 5-6 个十六进制值,因此匹配的字符总数为 11 或 12。
替换是一样的。
这是我的第一个 post 所以我希望它足够清楚。 在我将 CSV 文件读入 R 之前,我遇到了清理 CSV 文件的问题,我花了一整天时间寻找解决方案。
我的数据应该是两列的形式。第一列是一个由 10 位数字组成的时间戳,第二列是一个由 11 或 12 个字母和数字组成的 ID(前 6 个总是数字)。
例如:
logger10 |
0821164100 | 010300033ADD
0821164523 | 010300033ADD
0821164531 | 010700EDDA0F0831102744
010700EDDA0F|
会变成:
0821164100 | 010300033ADD
0821164523 | 010300033ADD
0821164531 | 010700EDDA0F
0831102744 | 010700EDDA0F
(请原谅中间的线条,那是我试图分隔列...)。
csv 文件似乎偶尔会缺少一个逗号,这意味着有时一行会像这样结束:
0923120531,010300033ADD0925075301,010700EDD00A
我的硬件在重新启动时也会添加单词 logger10
(或任何数字记录器),这会产生类似的问题,例如logger10logger100831102744
。
我想我已经设法解决了记录器文本问题(参见代码),但我确信这可以改进。另外,我真的不想删除任何数据。 我真正的麻烦是确保在 ID 之后的正确位置有一个换行符,如果没有,我想添加一个。我以为我可以为此使用正则表达式,但我很难理解它。
如有任何帮助,我们将不胜感激!
这是我的尝试:
temp <- list.files(pattern="*.CSV") #list of each csv/logger file
for(i in temp){
#clean each csv
tmp<-readLines(i) #check each line in file
tmp<-gsub("logger([0-9]{2})","",tmp) #remove logger text
pattern <- ("[0-9]{10}\,[0-9]{6}[A-Z,0-9]{5,6}") #regex pattern ??
if (tmp!= pattern){
#I have no idea where to start here...
}
}
这里是一些原始数据: 记录器01 0729131218,020700EE1961 0729131226,020700EE1961 0831103159,0203000316DB 0831103207,0203000316DB0831103253,010700EDE28C 0831103301,010700EDE28C 0831103522,010300029815 0831103636,010300029815 0831103657,020300029815
在此处粘贴您的正则表达式 https://regex101.com/ 以查看它是否捕获所有情况。 5 或 6 个字母或数字可能会造成问题,因为当记录器错过逗号时,它可能会捕获时间戳的第一位数字。如果正则表达式捕获所有情况,则在 tmp 字符串的末尾附加一个“\n”应该可以工作。
如果您想一次完成此操作:
(?:logger\d\d )?([\dA-F]{10}),?([\dA-F]{12}) ?
可以换成
\t\n
它的作用是选择性地查找那些流氓 logger01
条目(包括它后面的 space): 组后面的尾随 ?
意味着它可以匹配 0或 1 次:如果它 确实 匹配,它会匹配。如果它不存在,比赛就会继续进行。
之后,您查找(并捕获)恰好 10 个十六进制值(数字或 A-F
)。 ,?
表示如果逗号存在,它将匹配,但它也可以匹配 0 次或 1 次(使其可选)。
之后,查找(并捕获)恰好 12 个十六进制值。最后,为了摆脱任何奇怪的尾随 space,?
(space 字符后跟 ?
)将有选择地匹配尾随 space。
您的替换将替换第一个捕获组(10 个十六进制数字),添加制表符,替换第二个捕获组(12 个十六进制数字),然后换行。
您可以在 regex101 上看到这个正在使用以查看结果。您可以使用该页面左侧的 code generator
来获取一些预格式化的 PHP/Javascript/Python,您可以将其放入脚本中。
如果您从命令行执行此操作,可以使用 perl:
perl -pe 's/(?:logger\d\d )?([\dA-F]{10}),?([\dA-F]{12}) ?/\t\n/g'
如果是其他语言,您可能需要稍微调整一下以满足您的需要。
编辑
重新阅读 OP 和评论,一个稍微更严格的正则表达式可能是
(?:logger\d\d\ )?([\dA-F]{10}),?(\d{6}[\dA-F]{5,6})\ ?
我用更改更新了 regex101 link。
这仍然会查找前 10 个十六进制值,但现在只查找 6 位数字,然后是 5-6 个十六进制值,因此匹配的字符总数为 11 或 12。
替换是一样的。