代码之家  ›  专栏  ›  技术社区  ›  dax90

使用sed处理分隔文本文件

  •  2
  • dax90  · 技术社区  · 10 年前

    我有一个“;”分隔文件:

    aa;;;;aa
    rgg;;;;fdg
    aff;sfg;;;fasg
    sfaf;sdfas;;;           
    ASFGF;;;;fasg
    QFA;DSGS;;DSFAG;fagf
    

    我想用 \N . 结果应该是:

    aa;\N;\N;\N;aa
    rgg;\N;\N;\N;fdg
    aff;sfg;\N;\N;fasg
    sfaf;sdfas;\N;\N;\N         
    ASFGF;\N;\N;\N;fasg
    QFA;DSGS;\N;DSFAG;fagf
    

    我正在尝试使用sed脚本:

    sed "s/;\(;\)/;\\N\1/g" file1.txt  >file2.txt
    

    但我得到的是

    aa;\N;;\N;aa
    rgg;\N;;\N;fdg
    aff;sfg;\N;;fasg
    sfaf;sdfas;\N;;         
    ASFGF;\N;;\N;fasg
    QFA;DSGS;\N;DSFAG;fagf
    
    6 回复  |  直到 10 年前
        1
  •  5
  •   axiac    10 年前

    您不需要将第二个分号括在括号中,只需将其用作 \1 在替换字符串中。您可以使用 ; 在替换字符串中:

    sed 's/;;/;\\N;/g'
    

    正如您所注意到的,当它找到一对分号时,它会用所需的字符串替换它,然后跳过它,而不是再次读取第二个分号,这会使它插入 \N 每两个分号之后。

    一种解决方案是使用正面的表情;这个 regex /;(?=;)/ 但是 sed 不支持它们。

    但可以使用 已安装的 以简单的方式:复制搜索命令;第一个命令替换 ;; 具有 ;\N ,第二个处理均匀的外观。最终的结果是你需要的。

    该命令简单如下:

    sed 's/;;/;\\N;/g;s/;;/;\\N;/g'
    

    它复制上一个命令,并使用 ; 之间 g s 以分离它们。或者,您可以使用 -e 每个搜索表达式使用一次命令行选项:

    sed -e 's/;;/;\\N;/g' -e 's/;;/;\\N;/g'
    

    更新:

    OP在评论中询问 “如果我的文件有100列怎么办?”

    让我们看看它是否有效:

    $ echo "0;1;;2;;;3;;;;4;;;;;5;;;;;;6;;;;;;;" | sed 's/;;/;\\N;/g;s/;;/;\\N;/g'
    0;1;\N;2;\N;\N;3;\N;\N;\N;4;\N;\N;\N;\N;5;\N;\N;\N;\N;\N;6;\N;\N;\N;\N;\N;\N;
    

    看,妈妈!它起作用了! :-)


    更新#2

    我忽略了这样一个事实,即这个问题不需要替换 ;; 除了替换使用 ; 以分隔列。因此,当缺失的值出现在行的开头或结尾时,我的表达式不会修复它。

    正如OP在评论中友好地补充的那样 已安装的 命令是:

    sed 's/;;/;\\N;/g;s/;;/;\\N;/g;s/^;/\\N;/g;s/;$/;\\N/g'
    

    或(为了可读性):

    sed -e 's/;;/;\\N;/g;' -e 's/;;/;\\N;/g;' -e 's/^;/\\N;/g' -e 's/;$/;\\N/g'
    

    两个附加步骤将替换“;”当他们在行头或行尾找到它时。

        2
  •  3
  •   anubhava    10 年前

    你可以用这个 sed 带2的命令 s (替代)命令:

    sed 's/;;/;\\N;/g; s/;;/;\\N;/g;' file
    aa;\N;\N;\N;aa
    rgg;\N;\N;\N;fdg
    aff;sfg;\N;\N;fasg
    sfaf;sdfas;\N;\N;
    ASFGF;\N;\N;\N;fasg
    QFA;DSGS;\N;DSFAG;fagf
    

    或使用 查找正则表达式 在一个 perl 命令:

    perl -pe 's/(?<=;)(?=;)/\\N/g' file
    aa;\N;\N;\N;aa
    rgg;\N;\N;\N;fdg
    aff;sfg;\N;\N;fasg
    sfaf;sdfas;\N;\N;
    ASFGF;\N;\N;\N;fasg
    QFA;DSGS;\N;DSFAG;fagf
    
        3
  •  2
  •   Casimir et Hippolyte    10 年前

    主要问题是,不能在单个替换中使用多次相同的字符:

    s/;;/..../g :第二个 ; 不能在字符串中的下一场比赛中重复使用 ;;;

    如果您想使用sed而不使用类似Perl的正则表达式模式,则可以使用带有条件命令的循环 t :

    sed ':a;s/;;/;\\N;/g;ta;' file
    

    :a 定义标签“a”, ta 只有当有东西被替换时,才能使用此标签。

    对于 ; 在该行的末尾(并处理最终的尾随空白):

    sed ':a;s/;;/;\\N;/g;ta; s/;[ \t\r]*$/;\\N/1' file
    
        4
  •  1
  •   Kent    10 年前

    这款awk one liner可以满足您的需求:

    awk -F';' -v OFS=';' '{for(i=1;i<=NF;i++)if($i=="")$i="\\N"}7' file
    

    如果你真的想要这行: sfaf;sdfas;\N;\N;\N ,这行适合您:

    awk -F';' -v OFS=';' '{for(i=1;i<=NF;i++)if($i=="")$i="\\N";sub(/;$/,";\\N")}7' file
    
        5
  •  1
  •   NeronLeVelu    10 年前
    sed 's/;/;\\N/g;s/;\\N\([^;]\)/;\1/g;s/;[[:blank:]]*$/;\\N/' YourFile
    
    • 非递归、onliner、posix兼容

    概念:

    • 全部更改 ;
    • 收回不匹配的
    • 添加last的特殊情况 ; 在行尾之前有最终空格
        6
  •  1
  •   potong    10 年前

    这可能适用于您(GNU sed):

    sed -r ':;s/^(;)|(;);|(;)$/\2\3\\N\1\2/g;t' file
    

    有4种情况下可能出现空字段:在记录的开头、两个字段分隔符之间、空字段后面和记录的结尾。可以采用交替来满足senario 1、2和4,senario 3可以通过使用环路的第二次传递来满足( :;...;t ). 使用 g 旗帜

    推荐文章