Comportamento de divisão inesperado

1

Eu li sobre o comportamento de divisão do Awk aqui:

[...] the fs argument to the split function (see String Functions) shall be interpreted as extended regular expressions. These can be either ERE tokens or arbitrary expressions, and shall be interpreted in the same manner as the right-hand side of the ~ or !~ operator.

e:

If the right-hand operand is any expression other than the lexical token ERE, the string value of the expression shall be interpreted as an extended regular expression, including the escape conventions described above.

link

No entanto, notei um resultado inesperado com este código:

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

Espero que . represente qualquer caractere e que o resultado seja 6 . No entanto, todos os meus testes retornaram 2 . A execução deste código fornece o esperado 6 :

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

Testado com:

  • gawk
  • gawk --posix
  • mawk 1.3.4
  • mawk 1.3.3
  • nawk (original-awk)

Estou entendendo mal a documentação ou isso é um erro?

    
por Steven Penny 24.11.2018 / 15:41

1 resposta

3

Isto não é um erro; é só que o padrão não é claro o suficiente ao tentar codificar a prática existente.

O manual mawk (1) é mais explícito:

split(expr, A, sep) works as follows:

...

(2) If sep = " " (a single space), then <SPACE> is trimmed from the front and back of expr, and sep becomes <SPACE>. mawk defines <SPACE> as the regular expression /[ \t\n]+/. Otherwise sep is treated as a regular expression, except that meta-characters are ignored for a string of length 1, e.g., split(x, A, "*") and split(x, A, /*/) are the same.

Além disso, o manual do GNU awk do fontes atuais :

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

...

Splitting behaves identically to field splitting, described above. In particular, if r is a single-character string, that string acts as the separator, even if it happens to be a regular expression metacharacter.

Esta é a descrição do padrão do susv4:

An extended regular expression can be used to separate fields by assigning a string containing the expression to the built-in variable FS, either directly or as a consequence of using the -F sepstring option. The default value of the FS variable shall be a single <space>. The following describes FS behavior:

  1. If FS is a null string, the behavior is unspecified.
  2. If FS is a single character:

    a. If FS is <space>, skip leading and trailing <blank> and <newline> characters; fields shall be delimited by sets of one or more <blank> or <newline> characters.

    b. Otherwise, if FS is any other character c, fields shall be delimited by each single occurrence of c.

  3. Otherwise, the string value of FS shall be considered to be an extended regular expression. Each occurrence of a sequence matching the extended regular expression shall delimit fields.

Seu exemplo corresponde a 2.b.

Mesmo que isso mencione explicitamente FS , é o mesmo comportamento com qualquer argumento usado em vez disso, como o terceiro argumento para split em todas as implementações do awk, incluindo no caso em que esse argumento é um espaço.

É improvável que o comportamento mude, porque a variável FS é apenas uma string ( awk não tem objetos regexp, como javascript ou perl ; você não pode atribuir um regexp a uma variável, como em a=/./ ou $a=qr/./ ); é a função split (chamada implícita ou explicitamente) que interpreta seu argumento como descrito acima.

A origem desse comportamento pode ser compatível com o awk "antigo", em que FS (ou o terceiro argumento para split ) sempre foi tratado como um único caractere. Exemplo (no 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
    
por 24.11.2018 / 16:13