簡體   English   中英

使用sed處理帶分隔符的文本文件

[英]process a delimited text file with sed

我有一個 ”;” 分隔文件:

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

您不需要將第二個分號括在括號中,只是在替換字符串中將其用作\\1 你可以用; 在替換字符串中:

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

正如您所注意到的,當它找到一對分號時,它會用所需的字符串替換它,然后跳過它,而不是再次讀取第二個分號,這使得它在每兩個分號后插入\\N

一個解決方案是使用積極的前瞻; regex/;(?=;)/但是sed不支持它們。

但是可以通過簡單的方式使用sed解決問題:復制搜索命令; 第一個命令取代奇怪的外觀;; ;\\N ,第二個照顧均勻的外觀。 最終的結果是你需要的。

命令很簡單:

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

它復制了上一個命令並使用了; gs之間切斷它們。 或者,您可以為每個搜索表達式使用-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命令是:

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'

另外兩個步驟取代';' 當他們在開始或結束時找到它。

您可以將此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命令中使用lookarounds regex

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

主要問題是,對於單個替換,您不能使用多次相同的字符:

s/;;/..../g :第二個; 不能在字符串中的下一個匹配中重復使用;;;

如果你想使用sed而不使用類似Perl的正則表達式模式,你可以使用帶有條件命令t的循環:

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

:a定義了一個標簽“一”, ta去只有當事情已被替換這個標簽。

對於; 在行尾(並處理最終的尾隨空格):

sed ':a;s/;;/;\\N;/g;ta; s/;[ \t\r]*$/;\\N/1' file

這個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
sed 's/;/;\\N/g;s/;\\N\([^;]\)/;\1/g;s/;[[:blank:]]*$/;\\N/' YourFile
  • 非遞歸,在線,posix兼容

概念:

  • 改變一切;
  • 放回無與倫比的
  • 添加最后一個特例; 在行尾之前最終有空間

這可能適合你(GNU sed):

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

有4個可能出現空字段的情況:在記錄的開頭,2個字段分隔符之間,空字段后面的空字段和記錄的結尾。 可以采用輪換來滿足上述情況1,2和4,並且可以使用循環( :;...;t )通過第二次傳遞來滿足senario 3。 使用g標志可以在兩次傳遞中替換多個senarios。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM