如何使用 awk 中的正則運算式驗證檔案中的日期列?我的代碼似乎不適用于 awk。
我的代碼
awk -F '|' BEGIN {OFS=FS}
{ if
($1 ~ /^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}.\d{1,2}.\d{1,2} [AP]M\z/)
print
}' file > file.out
檔案內容——
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
06-JUN-2022|09876
2022-JAN-2011 22:12:33|23120
預期產出
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
uj5u.com熱心網友回復:
正如其他人指出的那樣,\d任何\z強制性 POSIX 工具都無法識別,包括 awk、sed 和 grep(GNU grep 除外-P)。
使用任何 POSIX awk:
$ awk '/^([0-9]{2}\/){2}[0-9]{4} ([0-9]{2}:){2}[0-9]{2} [AP]M\|/' file
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
或者,如果您愿意:
$ awk -F'|' '$1 ~ /^([0-9]{2}\/){2}[0-9]{4} ([0-9]{2}:){2}[0-9]{2} [AP]M$/' file
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
上面只是檢查輸入看起來像一個時間戳,所以它會接受無意義的日期和時間值,比如57/95/0000 35:72:65 PM. 要實際檢查輸入是否是有效的時間戳,在 GNU awk 中用于時間函式和第三個引數是match():
$ cat tst.awk
BEGIN { FS="|" }
match($1,/^([0-9]{2})\/([0-9]{2})\/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) ([AP]M)$/,t) {
if ( (t[7] == "PM") && (t[4] < 12) ) {
t[4] = 12
}
inDt = sprintf("d d d d d d",t[3],t[1],t[2],t[4],t[5],t[6])
secs = mktime(inDt)
outDt = strftime("%Y %m %d %H %M %S",secs)
if ( inDt == outDt ) {
print
}
}
$ awk -f tst.awk file
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
請注意該腳本的此輸出與給定此修改后的輸入檔案的第一個腳本的區別:
$ cat file
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
06-JUN-2022|09876
2022-JAN-2011 22:12:33|23120
57/95/0000 35:72:65 PM|nonsense date and time numbers
02/29/2020 05:10:20 AM|this is a leap year
02/29/2021 05:10:20 AM|this is a not leap year
$ awk -F'|' '$1 ~ /^([0-9]{2}\/){2}[0-9]{4} ([0-9]{2}:){2}[0-9]{2} [AP]M$/' file04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
57/95/0000 35:72:65 PM|nonsense date and time numbers
02/29/2020 05:10:20 AM|this is a leap year
02/29/2021 05:10:20 AM|this is a not leap year
$ awk -f tst.awk file
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
02/29/2020 05:10:20 AM|this is a leap year
如果您可以使用單個數字而不是始終為您提供的示例中所示的雙倍輸入,請將每個更改{2}為。{1,2}
uj5u.com熱心網友回復:
在and序列中不是有效GNU awk的正則運算式運算子(快速的網路搜索不會將它們顯示為其他幾種風格的有效正則運算式運算子,但絕不是詳盡的搜索)。\d\zawk
我建議用\dor[0-9]替換[[:digit:]]; 至于\z你可以嘗試\>或\y。
另一個問題是.在時間組件中用作通配符匹配;如果您知道所有時候都會使用冒號 ( :) 作為分隔符,那么我會使用顯式冒號。
將這些更改滾動到當前代碼中(并修復幾個剪切-粘貼/語法問題):
awk -F '|' 'BEGIN {OFS=FS}
{ if ($1 ~ /^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [AP]M\y/)
print
}'
這會產生:
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
筆記:
- 顯然(?)此代碼假定特定的日期/時間格式,因此...
- 此代碼不會匹配其他有效的日期/時間格式(例如,不會匹配
2021/12/31) - 的使用使
[0-9]您可以匹配無效日期和/或時間的字串,例如,此代碼將匹配99/99/2022和99:99:99);OP 可以通過限制在給定位置(例如,小時)可以匹配的數字系列來解決其中的一些問題,[0-2][0-9]但即使這樣也是有問題的,因為29將匹配但不是有效的小時 - 正如評論中提到的......驗證日期/時間是可行的,但需要更多代碼(或者運行網路搜索以
bash awk validate dates times獲取更多想法)
uj5u.com熱心網友回復:
awk -F'|' '{printf "%s",(match($1, /^[0-1][0-9]\/[0-3][0-9]\/[0-9]{4}.*[AP]M$/)) ? $0"\n" : "" }' file
04/21/2014 02:04:55 AM|34536
12/31/2021 03:29:15 AM|87612
uj5u.com熱心網友回復:
因為\z在字串末尾斷言位置,但在您的情況下,您有管道符號,我假設行程 ID,這意味著您的輸入字串和正則運算式之間不匹配。
如果您確定這就是該行包含的全部內容,您可以嘗試匹配 A/PM 之后的所有內容:
^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}.\d{1,2}.\d{1,2} [AP]M.*
否則,匹配直到下一個不同的分隔符。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/492673.html
