使用 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。

替换是一样的。