2017-08-23 20 views
1

我試圖格式化下面的文本文件格式,創紀錄的訂單會總是這樣文本文件中使用正則表達式

Dept 0100 Batch Load Errors for 8/16/2016 4:45:56 AM 

Case 1111111111 
Rectype: ABCD 
    Key:UMUM_REF_ID=A12345678,UMSV_SEQ_NO=1 
     UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID 

Case 2222222222 
Rectype: ABCD 
    Key:UMUM_REF_ID=B87654321,UMSV_SEQ_NO=2 
     UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID 
     NTNB ERROR :Invalid Value      NTNB_MCTR_SUBJ=AMOD 

Case 3333333333 
Rectype: WXYZ 
    Key:UMUM_REF_ID=U19817250,UMSV_SEQ_NO=2 
     UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID 

作爲輸出

1111111111~ABCD~UMUM_REF_ID=A12345678,UMSV_SEQ_NO=1~UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID 
2222222222~ABCD~UMUM_REF_ID=B87654321,UMSV_SEQ_NO=2~UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID|NTNB ERROR :Invalid Value NTNB_MCTR_SUBJ=AMOD 
3333333333~WXYZ~UMUM_REF_ID=U19817250,UMSV_SEQ_NO=2~UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID 

我想正則表達式如下

sed -r '/^Case/!d;$!N;/\nRectype/!D;s/\s+$/ /;s/(.*)\n(.*)/\2\1\n\1/;P;D' file.txt 

但這只是工作,直到Rectype行,無法實現休息。

謝謝。

+0

所需輸出的第二行中的空格看起來比輸入的相應行中的空格長。這是打算嗎? – Beta

+0

@Beta:我只是更新了所需的輸出,需要修剪額外的空間(如果有的話) – vin

+0

關於如何連接Key:的規則是什麼?第一行和第二行是用'〜'分隔的字段,後面的行用'|'連接起來?或者,以'N'開始的行總是用'|'加入,而其他所有用'〜'加入?或者是其他東西?並且所有> 2個空格的字符串應該縮小到2還是縮小到1? – ghoti

回答

0

在我看來,你並不是真的在尋找正則表達式。您正在尋找文本重新格式化,並且您似乎選擇了sed中的正則表達式匹配作爲您處理字段的方法。

閱讀關於XY problems here。值得慶幸的是,您已經包含了原始數據和期望的輸出,對於新的StackOverflow成員來說這真是太棒了。 (真的!你好!)所以我可以推薦一種替代品,它可能對你更好。

這是awk。像sed一樣,另一種命令行工具幾乎安裝在地球上每個類Unix系統上。

$ awk -v RS= -v OFS="~" '!/^Case/{next} {sub(/^Key:/,"",$5); key=$5; for (f=6;f<=NF;f++) { if ($f=="NTNB") key=key "|"; else if ($f=="UMSV") key=key OFS; else key=key " "; key=key $f } print $2,$4,key}' inp2 
1111111111~ABCD~UMUM_REF_ID=A12345678,UMSV_SEQ_NO=1~UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID 
2222222222~ABCD~UMUM_REF_ID=B87654321,UMSV_SEQ_NO=2~UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID|NTNB ERROR :Invalid Value NTNB_MCTR_SUBJ=AMOD 
3333333333~WXYZ~UMUM_REF_ID=U19817250,UMSV_SEQ_NO=2~UMSV ERROR :UNITS_ALLOW must be > or = UNITS_PAID 

以下是發生了什麼事情。

  • awk -v RS= - 這很重要。它設置了一個「null」記錄分隔符,它告訴awk我們正在處理多行記錄。記錄以空白行結束,並且該記錄內的字段由空格分隔。 (空格,製表符,換行符。)
  • -v OFS="~" - 爲了方便起見,設置代字號的輸出字段分隔符。
  • $1!="Case"{next} - 如果當前記錄的第一個字段中沒有「Case」一詞,那麼它不是我們可以處理的一行,因此請跳過它。
  • sub(/^Key:/,"",$5); key=$5; - 從第五個字段的開始處修整字Key,將字段保存爲變量。
  • for (f=6;f<=NF;f++) { - 設置適當的字段分隔符 - 通過剩餘字段
  • if ($f=="NTNB") key=key "|";步驟。
  • else if ($f=="UMSV") key=key OFS; - ...
  • else key=key " "; - 或空間,如果文本看起來不像一個新字段。
  • key=key $f } - 最後,將當前字段添加到我們的運行變量
  • print $2,$4,key} - 並打印所有內容。

注意:這不會做的一件事就是維護間距,就像您在問題的「預期輸出」中所顯示的一樣。兩個或兩個以上的空格總是會縮小到一個空格,因爲在每個記錄中,字段之間用空格分隔。


UPDATE每評論

Windows使用\r\n(CRLF)結束線,而Unix/Linux上使用剛剛\n(LF)。由於您的文件是在Windows中生成的,因此「空白」行實際上包含一個不可見的CR,並且從不會看到記錄分隔符。

要查看文件的「真實」內容,可以使用諸如hexdumpod之類的工具。例如:

$ printf 'foo\r\nbar\r\n' | od -c 
0000000 f o o \r \n b a r \r \n 
0000012 

在你的情況,只需運行:

$ od -c filename | less 

(或者使用more如果少不可用)

許多系統有一個叫做dos2unix提供一個包,可以轉換文本格式。

如果您沒有dos2unix可用,您應該能夠使用其他工具實現相同的功能。在GNU sed的:

sed -i 's/\r$//' filename 

或者其他SED變種,但支持的格式取代(讀man sed看到,如果你有一個-i選項)的殼(如bash)的:

sed $'s/\r$//' inputfile > outputfile 

或者少一點精確,因爲它會刪除所有的CR即使他們在該行的結束不是,你可以使用tr

tr -d '\015' <inputfile> outputfile 

或者,如果Perl是可用,您可以使用替換表達式這幾乎等同於一個sed的(Perl文檔是現成的告訴你什麼選擇呢):

perl -i -pe 's/\r\n$/\n/g' filename 

祝你好運!

+0

感謝您提出的解決方案,它對我在這裏提到的文件格式(我手動創建此示例文件)非常適用。但是當我在具有相同格式和相同字段標籤的另一個文件上運行此代碼時,我沒有得到期望的結果。我試圖運行代碼的文件是由Windows操作系統創建的,因此可能會有一些垃圾值代替空格和新行。很遺憾,我無法在這裏上傳文件。有沒有什麼辦法可以確定它包含的內容,因此我可以對其進行格式化以使此代碼正常工作。 – vin

+0

很高興這有幫助。是的,你已經擊中了頭 - 我已經添加了更新,而不是在評論中提供解釋和解決方案。 – ghoti

+0

哇!運行你提供的命令後,我可以在文件中看到很多\ r \ n。我刪除了\ r並運行了您的解決方案。一切順利。 – vin