Regular-Expression

ksh中數字驗證的正則表達式模式問題

  • May 26, 2022

我正在編寫一個 ksh 腳本來驗證該列是否為數字。正則表達式模式在配置文件中定義,例如\d+.\d+. d但是當我使用模式時這不起作用。然而[0-9]{1,9}正在工作。對此有何見解?

  • 這是我正在使用的 ksh 版本:
$ ksh --version
 version         sh (AT&T Research) 93u+ 2012-08-01
  • 模式比較的程式碼片段。如果我提供$col_patt\d+不會起作用但[0-9]{1,}會起作用
val=$(awk -F "$sep" -v n="$col_pos" -v m="$col_patt" 'NR!=1 && $n !~ "^" m "$" {
                        printf "%s:%s:%s\n", FILENAME, FNR, $n > "/dev/stderr"
                        count++
                      }
                      END {print count+0}' "$cp_input" 2>> $script_path/errors_${file_name_patt}.log
                      )
  • 這是使用的模式:\d*\.\d+

各種實用程序、語言、正則表達式/模式庫和 API 支持不同的運算符/萬用字元。

\d是匹配十進制數字的 perl 正則表達式運算符(通常是0123456789,但在某些情況下可以匹配其他十進制數字(Unicode中有數百個例如0123456789 ٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८୦୧୨୩୪୫୬୭୮୯୦୧୨୩୪୫୬୭୮୯1225501234567899១123456789 ٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८𞅅𞅆𞅇𞅈𞅉𞋰𞋱𞋲𞋳𞋴𞋵𞋶𞋷𞋸𞋹𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹 )).

自從 perl 在 80 年代引入該運算符以來,一些正則表達式引擎也紛紛效仿,但遠非如此。perl我知道的支持它的旁邊是:

  • vim(不在括號表達式內)。
  • PCRE庫(在許多工具和語言中使用)
  • pythonruby正則表達式或更一般的正則表達式,旨在覆蓋大部分或擴展 PCRE 表達式。
  • ast-openksh93 使用的正則表達式,或者當 ksh93 已被編譯為 ast-open 的一部分並且您已執行/或將其放在前面以啟用它們時, ksh93 的grep/內置函式。在 ksh93 glob 中,只有在其擴展運算符之一(其中可以是, , …)中找到時才被辨識。將匹配但不匹配(不在括號表達式內)。sed``builtin grep``builtin sed``/opt/ast/bin``$PATH``\d``x(...)``x``@``+``~``[[ 1 = @(\d) ]]``[[ 1 = \d ]]

POSIX基本擴展正則表達式和 shell 文件名模式(例如用於 shell 文件名生成或fnmatch(), 或find -path/-name模式)中的 POSIX 等效項是[[:digit:]]. 這意味著相同,[0123456789]但您會發現一些與其他數字匹配的系統。

還有[0-9]一個匹配 0 到 9 之間的字元。同樣,這應該包括[0123456789] 但通常包括更多。POSIX 只保證與/語言環境中[0-9]的相同。[0123456789]``C``POSIX

zshglobs 還支持<x-y>運算符匹配表示特定範圍內的十進制數的字元串。<3-12>例如將匹配006, 11, 012, 並且與’s<->相同(儘管只有 0123456789 位)。perl``\d+

也不是所有的正則表達式引擎都能辨識+。那個來自70 年代後期的egrep/ ,並且(與 相反)不能添加到已經存在的正則表達式引擎(如,或)中,因為這會破壞向後兼容性和正在尋找字元的腳本。awk``\d``grep``sed``vi``grep +``+

所有正則表達式引擎(不是 glob)都可以辨識.匹配任何單個字元(與?glob 運算符相同)的運算符,就像 60 年代的原始實現中那樣。

匹配由一個或多個 ASCII 十進制數字後跟一個文字.,然後是 1 個或多個 ASCII 十進制數字組成的字元串的最便攜的正則表達式是:

^[0123456789][0123456789]*[.][0123456789][0123456789]*$

雖然請注意,perl那也將匹配12.3<newline>。你需要^\d+\.\d\Z避免它。

既然您現在已經澄清了該工具是awk,我不知道任何awk支持\d作為正則表達式運算符的實現。都會支持[0123456789]+[0-9]儘管它在 C 語言環境之外匹配的內容取決於實現,但所有都將支持,大多數將支持[[:digit:]].

此外,要將數據傳遞給awk可能包含反斜杠字元(恰好是您的情況),您應該避免-v這樣做,因為一級反斜杠轉義擴展¹(\n變成換行符\\進入\\d進入\dd生成錯誤取決於實施)。

所以在這裡,你想要:

val=$(
 RE="$col_patt" awk -F "$sep" -v n="$col_pos" '
   BEGIN {m = ENVIRON["RE"]}
   NR!=1 && $n !~ "^" m "$" {
     printf "%s:%s:%s\n", FILENAME, FNR, $n > "/dev/stderr"
     count++
   }
   END {print count+0}
   ' "$cp_input" 2>> "$script_path/errors_${file_name_patt}.log"
)

並確保包含與您的實現$col_patt辨識的語法兼容的正則表達式。awk

col_patt='[0123456789]+\.[0123456789]'

至少應該沒問題。


¹ 最新版本的 GNU 實現awk也存在以 . 開頭@/和結尾的值的問題/。看看如何awk -v var='@/x/' 'BEGIN{print var}'輸出x而不是@/x/那裡

引用自:https://unix.stackexchange.com/questions/654372