web-dev-qa-db-ja.com

予期しない分割動作

ここでAwkの分割動作について読みました:

[...]split関数(文字列関数を参照)へのfs引数は解釈されます。拡張正規表現として。これらは、[〜#〜] ere [〜#〜]トークンまたは任意の式のいずれかであり、右と同じ方法で解釈されます- ~または!~演算子の手側。

そして:

右側のオペランドが字句トークン[〜#〜] ere [〜#〜]以外の式の場合、式の文字列値上記のエスケープ規則を含む、拡張正規表現として解釈されるものとします。

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html#tag_20_06_13_04

しかし、私はこのコードで予期しない結果に気づきました:

BEGIN {
  print split("te.st", q, ".")
}

.は任意の文字を表し、結果は6になると思います。しかし、私のテストはすべて2を返しました。このコードを実行すると、期待される6が得られます。

BEGIN {
  print split("te.st", q, /./)
}

テスト済み:

  • gawk
  • gawk --posix
  • mawk 1.3.4
  • mawk 1.3.3
  • nawk(オリジナル-awk)

ドキュメントを誤解していますか、それともエラーですか?

1
Steven Penny

これはエラーではありません。既存の慣行を成文化しようとしている間、基準が十分に明確ではないというだけです。

Mawk(1)のマニュアルはより明確です。

split(expr, A, sep)は次のように機能します。

.。

(2)_sep = " "_(単一のスペース)の場合、_<SPACE>_はexprの前後からトリミングされ、sepは_<SPACE>_になります。 mawkは、_<SPACE>_を正規表現_/[ \t\n]+/_として定義しています。それ以外の場合、sepは正規表現として扱われます。ただし、長さ1の文字列ではメタ文字が無視されます(例:split(x, A, "*")split(x, A, /*/)は同じです。

また、GNU awkマニュアル 電流源

split(s, a [, r [, seps] ])

.。

分割は、上記のフィールド分割と同じように動作します。特に、rが1文字の文字列である場合、その文字列は、正規表現のメタ文字であっても、区切り文字として機能します。

これはsusv4からの説明です 標準

拡張正規表現を使用して、式を含む文字列を組み込み変数[〜#〜] fs [〜#〜]に割り当てることにより、フィールドを区切ることができます。 -)、直接または_-F sepstring_オプションを使用した結果として。 [〜#〜] fs [〜#〜]変数のデフォルト値は単一の<スペース>でなければなりません。以下に、[〜#〜] fs [〜#〜]の動作について説明します。

  1. [〜#〜] fs [〜#〜]がnull文字列の場合、動作は指定されていません。
  2. [〜#〜] fs [〜#〜]単一文字の場合-):

    a。 [〜#〜] fs [〜#〜]が<space>の場合、先頭と末尾の<blank>文字と<newline>文字をスキップします。フィールドは、1つ以上の<blank>または<newline>文字のセットで区切られます。

    b。それ以外の場合、[〜#〜] fs [〜#〜]が他の文字cである場合、フィールドはcが1回出現するたびに区切られます。

  3. それ以外の場合、[〜#〜] fs [〜#〜]の文字列値は拡張正規表現と見なされます。拡張正規表現に一致するシーケンスが出現するたびに、フィールドが区切られます。

あなたの例は2.bに一致します。

それがFSに明示的に言及している場合でも、その引数がスペースである場合を含め、すべてのawk実装でsplitの3番目の引数として代わりに使用される引数と同じ動作です。

FS変数は単なる文字列であるため(awkにはjavascriptPerlなどの正規表現オブジェクトがないため、動作が変わる可能性はほとんどありません。 _a=/./_または_$a=qr/./_のように、正規表現を変数に割り当てることはできません。上記のように引数を解釈するのはsplit関数(暗黙的または明示的に呼び出されます)です。

この動作の原因は、FS(またはsplitの3番目の引数)が常に単一の文字として扱われていた「古い」awkとの互換性である可能性があります。例(unix v7):

_$ awk 'BEGIN{FS="."; print split("foo.bar.baz", a, "bar"); print a[2] }'
3
ar.
$ awk 'BEGIN{FS="."; print split("foo.bar.baz", a, /bar/); print a[2] }'
awk: syntax error near line 1
awk: illegal statement near line 1
Bus error - core dumped
_
3
mosvy