2014-11-22 47 views
1

我的輸入文件是GAWK - 有條件的(即依賴於正則表達式匹配)查找/一些轉換器功能替代

input.txt中

News A 1 B 2h 0m 1s C text1 
100 A 2 B 120m 1s C text2 
Show A 3 B 450s C text3 
Tom A 4 B 0:30 C text4 
Laura A 5 B 20 C text5 
Something A 6 B 1h 100m 70s C text6 
50 A 7 B 10s C text7 

(你看怪異的時間格式在第6行,但這是故意的,只是爲了演示,以簡化邏輯,而不需要額外的0-59)。

我想下面的正則表達式適用於每一行:

^(.*?)\sA\s(.*?)\sB\s(.*?)\sC\s(.*?)$ 

注意語法\3。有效的變體:

  • \d{1,}h \d{1,}m \d{1,}s
  • \d{1,}m \d{1,}s
  • \d{1,}s
  • \d{1,}等於\d{1,}s

我需要將其轉換成秒,但如果這部分無法通過此驗證,保持原樣。無論如何,讓我們將結果命名爲$sec

我需要定義以下的正則表達式的變量:

$price == '\d{1,} ', $names == 'Bob|Tom|Laura|Sandra', $tags == 'News|Show'(或(?:regex)語法,我不知道哪個是更好地在這裏)

然後,替換爲以下行:

  • 如果\1 ~ $price

    "ID: \1; time: $sec seconds; description: \1 – buy for $\1!

  • 如果\1 ~ $names

    description: \4 from @\1; time: $sec seconds

  • 如果\1 ~ $tags

    ID: \2; #\1; time: $sec seconds; description: \4

  • 否則(如果\1不匹配任何預定義的正則表達式的變量,或多於一個的可變匹配) :

    ID: \2; time: $sec seconds; \1; description: \4

所以輸出文件應

輸出。TXT

ID: 1; #News; time: 7201 seconds; description: text1 
ID: 2; time: 7201 seconds; description: text2 – buy for $100! 
ID: 3; #Show; time: 450 seconds; description: text3 
description: text4 from @Tom; time: 0:30 
description: text5 from @Laura; time: 20 seconds 
ID: 6; time: 9670 seconds; Something; description: text6 
ID: 7; time: 10 seconds; description: text7 – buy for $50! 

我用這個代碼:

gawk -F '\\|' 'function _time(str) { 
if (str ~ /([[:digit:]]+)h\s([[:digit:]]+)m\s([[:digit:]]+)s/) { 
match(str, /([[:digit:]]+)h\s([[:digit:]]+)m\s([[:digit:]]+)s/, arr) 
return arr[1]*3600+arr[2]*60+arr[3] } 
else if (str ~ /([[:digit:]]+)m\s([[:digit:]]+)s/) { 
match(str, /([[:digit:]]+)m\s([[:digit:]]+)s/, arr) 
return arr[1]*60+arr[2] } 
else if (str ~ /([[:digit:]]+)s/ || str ~ /([[:digit:]]+)/) { 
match(str, /([[:digit:]]+).*?/, arr) 
return arr[1] } 
else 
return str } 
match($0, /^(.*?)\sA\s(.*?)\sB\s(.*?)\sC\s(.*?)$/, _f) 
{ if (_f[1] ~ /[[:digit:]]+/) { 
printf "ID: %s; time: %s seconds; description: %s – buy for $%s\n", _f[2], _time(_f[3]), _f[4], _f[1] } 
else if (_f[1] ~ /Bob|Tom|Laura|Sandra/) { 
printf "description: %s from %s; time: %s seconds\n", _f[4], _f[1], _time(_f[3]) } 
else if (_f[1] ~ /News|Show/) { 
printf "ID: %s; #%s; time: %s seconds; description: %s\n", _f[2], _f[1], _time(_f[3]), _f[4] } 
else { 
printf "ID: %s; time: %s seconds; %s; description: %s\n", _f[2], _time(_f[3]), _f[1], _f[4] } }' input.txt > output.txt. 

,得到了四個方面的問題。

  1. 爲什麼我在輸出行之前看到輸入行?我希望輸入行是替換爲與結果行!
  2. 爲什麼我在第8條輸出線看到0 seconds?我預計會看到0:30 seconds。爲什麼0:30匹配/([[:digit:]]+)s/ || /([[:digit:]]+)/)?我預計else return str在這裏行動(保持0:30原樣)。
  3. 我使用if (_f[1] ~ /regex/)語法,但我不知道如何將/regex/放入變量。當我把它變成變量時,它不起作用。
  4. 我不知道AWK如何工作的內部。是否每條件測試?如果是,_f[1]匹配多個條件時應該怎麼做(if (_f[1] ~ /X|A/) { ... } else if (_f[1] ~ /A|B/) { ... })?我想把這個案例放入else {}。如果不是,我會選擇立即打印第一場比賽的結果,以提高表現。

附加說明:我使用Cygwin 命令行,而無需使用單獨的.awk文件的代碼。

+0

這GAWK的版本?對於0:30,它與你最後一個正則表達式'/([[:digit:]] +)/)'相匹配,因爲0是一個數字,你用一個或多個數字進行測試。你可以通過指定正則表達式的開始和結束來得到更好的結果,例如:'/^[[:digit:]] + $ /'創建捕獲組的括號在比較中是無用的。其餘的我會做測試,起初它不適用於我的gawk版本3.1.7 – Tensibai 2014-11-22 10:53:07

+1

我看不到樹林。我想你的主要問題是如何將人類可讀的時間戳轉換爲秒,不是嗎? – Jdamian 2014-11-22 11:04:49

+0

而不是'/ regex /',你可以'match($ 0,regex)' – 2014-11-22 15:39:02

回答

0

嘗試設置FS:

awk '{print "timestamp:", $3}' FS=' (A|B|C) ' input.txt 
+0

我解決了所有這些問題,除了一個,但我會問,作爲一個明確的,單獨的問題 – 2014-11-24 06:43:25