首页 文章

TCL多捕获组用于使用regexp简化csv字符串解析

提问于
浏览
0

我正在尝试使用TCL regexp解析简化的CSV格式 . 我选择regexp over split来执行基本格式一致性测试 .

我的问题是我想使用计数量词,但想从匹配中排除',' .

我的测试线:

set line "2017/08/21 16:06:20.0, REALTIME, late by  0.3, EOS450D,   1/640, F/8.0, ISO   100, Partial 450D 0.0%"

到目前为止,我有:

regexp -all {(?:([^\,]*)\,){8}} $line dummy date tm off cam exp fnum iso com

我的思考过程是:为所有不逗号到下一个逗号的字符获取匹配组 . 现在我想匹配这8次,所以我把它放入一个非捕获组,然后是一个计数量词 . 但这就失去了目的,因为现在没有什么是匹配的 . 我需要的是一种让匹配通过CSV 8次并捕获文本而不是逗号的方法 .

我的CSV简化如下 . CSV中没有带引号的字符串CSV中没有空条目

我已经检查了谷歌的csv匹配,但由于允许CSV内容中的特殊情况,大多数点击率都太过分了 .

谢谢,格特

1 回答

  • 2

    regexp 命令中, -all 开关与匹配变量之间的交互是在最后一次匹配迭代中捕获的值用于填充变量 . 这意味着您无法通过拥有一个捕获组并将其迭代匹配八次来填充八个变量 .

    您的正则表达式无论如何都不匹配,因为它在最后一个字段后需要逗号 .

    对于此特定示例,您可以使用调用

    % regexp -all -inline {[^,]+} $line
    {2017/08/21 16:06:20.0} { REALTIME} { late by  0.3} { EOS450D} {   1/640} { F/8.0} { ISO   100} { Partial 450D 0.0%}
    

    这意味着匹配不是逗号的所有字符组(请注意逗号不是特殊的:您不需要转义它)并将它们作为列表返回 .

    如您所述,这与使用相同

    % split $line ,
    

    (这也快了约五倍) .

    您不想使用 split ,因为您想要进行一些验证:不清楚您想要做什么形式的验证,但您可以轻松验证找到的字段数:

    % set fields [split $line ,]
    % if {[llength $fields] ne 8} {puts stderr "wrong number of fields"}
    

    您可以将字段存储在变量中并单独验证它们,这比在提取变量时同时验证所有字段要容易得多:

    lassign $fields date tm off cam exp fnum iso com
    if {![regexp {ISO\s+\d+} $iso]} {puts stderr "in search of valid ISO"}
    

    最好的方法仍然是使用 csv 包拆分数据字符串 . 即使你现在只想使用这个简化的CSV,比你想象的更快,比如说允许带有逗号的字段 .

    package require csv
    set fields [::csv::split $line]
    

    文档:csv (package)iflassignllengthpackageputs,_ regexpsetsplitSyntax of Tcl regular expressions

    ETA: 摆脱前导/尾随空格 . 这有点不寻常,因为CSV数据通常被安排为由分隔符分隔的严格重要文本字段 . 如果有任何要修剪的内容,通常在保存数据时完成 .

    一个好方法是将匹配的组放在 lmap / string trim 过滤器中:

    lmap field [regexp -all -inline {[^,]+} $line] {string trim $field}
    

    另一种方法是先删除逗号周围的空格,然后拆分:

    split [regsub -all {\s*,\s*} $line ,] ,
    

    您可以使用通过正则表达式拆分的 split 的Tcllib变体:

    package require textutil
    ::textutil::splitx $line {\s*,\s*}
    

    您还可以替换 [^\s,][^,]*[^\s,] 的早期正则表达式(不匹配少于两个字符的字段) . 这是一个正则表达式,即将变得过于复杂而无法使用 .

相关问题