Regex 如何用逗号作为字段分隔符,用awk分隔csv列?

Regex 如何用逗号作为字段分隔符,用awk分隔csv列?,regex,csv,awk,ubuntu-18.04,Regex,Csv,Awk,Ubuntu 18.04,我的正则表达式在带有awk的csv文件中不起作用,awk位于字段分隔符上 我的csv由逗号(,)分隔,但某些字段本身也有逗号 data.csv类似于: t1,t2,t3,t4 field without comma,f02,f03,f04 field, with comma,f12,f13,f14 field without comma,f22,f23,f24 field without comma,f22,f23,f34 如果我们在字段中看到逗号f12、f13、f14,我们有两种逗号: 逗号

我的正则表达式在带有awk的csv文件中不起作用,awk位于
字段分隔符上

我的csv由逗号(
)分隔,但某些字段本身也有逗号

data.csv
类似于:

t1,t2,t3,t4
field without comma,f02,f03,f04
field, with comma,f12,f13,f14
field without comma,f22,f23,f24
field without comma,f22,f23,f34
如果我们在
字段中看到逗号f12、f13、f14,我们有两种逗号:

  • 逗号是数据的一部分(在字段内部),如
    字段,带有逗号,以及
    
  • 逗号用于分隔字段
    、f12、f13、f14
  • 所以我尝试了awk,使用
    -F
    和:

    我的策略是:
    字段分隔符
    必须是逗号
    \,
    在没有单词边界的情况下
    \B

    因此,我的命令没有输出
    结果.csv
    。但发出了警告:

    gawk: warning: escape sequence `\B' treated as plain `B'
    gawk: warning: escape sequence `\,' treated as plain `,'
    
    所需的
    result.csv
    将删除重复的行,如:

    t1,t2,t3,t4
    field without comma,f02,f03,f04
    field, with comma,f12,f13,f14
    field without comma,f22,f23,f24
    
    使用GNU awk:

    awk -F ',[^ ]' '!seen[$2]++' data.csv
    
    输出:

    t1,t2,t3,t4 field without comma,f02,f03,f04 field, with comma,f12,f13,f14 field without comma,f22,f23,f24 t1、t2、t3、t4 不带逗号的字段,f02、f03、f04 字段,带逗号,f12、f13、f14 不带逗号的字段,f22、f23、f24 使用GNU awk:

    awk -F ',[^ ]' '!seen[$2]++' data.csv
    
    输出:

    t1,t2,t3,t4 field without comma,f02,f03,f04 field, with comma,f12,f13,f14 field without comma,f22,f23,f24 t1、t2、t3、t4 不带逗号的字段,f02、f03、f04 字段,带逗号,f12、f13、f14 不带逗号的字段,f22、f23、f24
    在没有GNU awk的情况下,使用数据,您可以使用
    gsub
    ,“
    字符串替换为一些不冲突的字符,例如
    ”,“
    ”,“
    上的字段按常规分开,然后再次使用
    gsub
    恢复字段中的逗号(例如
    ,“
    )。例如:

     awk -F, -v OFS=, '
        { gsub(/, /,"__"); for (i = 1; i <= NF; i++) gsub(/__/,", ", $i) }
        !seen[$0]++
    ' file.csv
    

    在没有GNU awk的情况下,使用数据,您可以使用
    gsub
    ,“
    字符串替换为一些不冲突的字符,例如
    ”,“
    ”,“
    上的字段按常规分开,然后再次使用
    gsub
    恢复字段中的逗号(例如
    ,“
    )。例如:

     awk -F, -v OFS=, '
        { gsub(/, /,"__"); for (i = 1; i <= NF; i++) gsub(/__/,", ", $i) }
        !seen[$0]++
    ' file.csv
    

    如果目的是使用
    t2
    列作为键值,那么您可以这样做:

    $ awk -F, '!seen[$(NF-2)]++' data.csv
    t1,t2,t3,t4
    field without comma,f02,f03,f04
    field, with comma,f12,f13,f14
    field without comma,f22,f23,f24
    
    如果要使用
    t1
    列作为键,那么您可以这样做:

    $ awk '{key=$0; sub(/(,[^,]+){3}$/,"",key)} !seen[key]++' data.csv
    t1,t2,t3,t4
    field without comma,f02,f03,f04
    field, with comma,f12,f13,f14
    

    如果是其他问题,请澄清您的问题并更新示例。

    如果目的是使用
    t2
    列作为键值,则您可以这样做:

    $ awk -F, '!seen[$(NF-2)]++' data.csv
    t1,t2,t3,t4
    field without comma,f02,f03,f04
    field, with comma,f12,f13,f14
    field without comma,f22,f23,f24
    
    如果要使用
    t1
    列作为键,那么您可以这样做:

    $ awk '{key=$0; sub(/(,[^,]+){3}$/,"",key)} !seen[key]++' data.csv
    t1,t2,t3,t4
    field without comma,f02,f03,f04
    field, with comma,f12,f13,f14
    


    如果是其他问题,请澄清您的问题并更新示例。

    这不是有效的CSV文件。如果字段包含逗号,则需要将其括在引号中。否则,无法判断逗号在字段中而不是分隔符。@Barmar,我同意这不是有效的csv(需要分隔符、分隔符、转义字段内容中的字符等)。但事实上,这就是数据。即便如此,看看我对两种逗号的观察。如果逗号左右各有两个单词(单词=字符+数字+下划线),则它是一个分隔符;如果逗号只有一个单词,那么它就是一个内容。我的问题是正则表达式没有逃逸
    \B
    \,
    uniq data.csv
    ?@Cyrus,我不能在这里使用
    uniq
    ,因为所有行都是唯一的。这里的Awk需要:按正则表达式(
    -F
    )分隔列,获取一列用作键(
    $2
    ),过滤每个列(
    !seen
    )并输出所有列。
    Awk
    不使用PCRE,它不支持许多转义序列。这不是有效的CSV文件。如果字段包含逗号,则需要将其括在引号中。否则,无法判断逗号在字段中而不是分隔符。@Barmar,我同意这不是有效的csv(需要分隔符、分隔符、转义字段内容中的字符等)。但事实上,这就是数据。即便如此,看看我对两种逗号的观察。如果逗号左右各有两个单词(单词=字符+数字+下划线),则它是一个分隔符;如果逗号只有一个单词,那么它就是一个内容。我的问题是正则表达式没有逃逸
    \B
    \,
    uniq data.csv
    ?@Cyrus,我不能在这里使用
    uniq
    ,因为所有行都是唯一的。这里的Awk需要:用正则表达式(
    -F
    )分隔列,得到一列用作键(
    $2
    ),过滤每一列(
    !seen
    )并输出所有列。
    Awk
    不使用PCRE,它不支持许多转义序列。在一般情况下,我们需要使用替换值(这里是它的
    )“\
    ),保证不会出现在数据中。考虑这样的CSV线路的结果:<代码> FieldSyOutOutuxCua,2,3,4< /代码>是的,谢谢,我很清楚,“用您的数据”和“替换<代码>”,“字符串与一些非冲突字符”。这并不是为了修复所有情况,而是盲目地应用于所有情况。FWIW我通常使用
    RS
    作为“非冲突字符”,因为在这种情况下,RS是一个字符(或非regexp字符串(它不能出现在当前记录中)。有意义的是,您消除了将用于括起非贪婪选择的内容(例如
    ){'
    '}
    ),然后设置搜索范围的开始和结束,最后是
    “{abc}def}”
    ,允许对括号之间的内容进行
    匹配
    结果是一个非贪婪的匹配。很高兴我在那里看到了多层次的思考过程,如果没有更多的经验,这将不会很明显。欢迎您,但深入思考的功劳归于@EdMorton。我打赌我从评论中学到的东西与我希望帮助他人得到答案的东西一样多。一般来说,我们需要使用一个保证值(这里是它的代码>”“< /代码>”,它保证不出现在数据中。考虑CSV线这样的结果:<代码> FieldSyOnOutuxa逗号,2,3,4/代码>是的,谢谢,我想它是WA。