A expressão ERE regex para split () entre um delimitador e um fim de palavra

5

Estou usando um longo script gawk 3.1.6 para fazer uma conversão complexa do texto de remarcação do Zim no código do GtkDialog e estou preso no seguinte problema ...

Exemplo de entrada ASCII ...

[[link|label label]] [[link]] @tag more text

Teste de linha de comando para encontrar o regex certo ...

re="[][][][]"; echo '[[link|label label]] [[link]] @tag more text' | awk -v RE=$re '{split($0,A,RE); printf "\n(" A[1] ")(" A[2] ")(" A[3] ")(" A[4] ")(" A[5] ")(" A[6] ")(" A[7] ")(" A[8] ")\n"}'

O regex "[][][][]" divide muito bem os dois formulários de hyperlink, então isso não é um problema.

It would be more understandable if we could divided it in two -- "[][]" and "[][]". We are looking for either "[[" or "]]" to split on. The order of the characters in the class have to be reversed to comply with class meta-character restrictions.

O problema está em dividir o "@tag" em apenas "tag". "tag" pode ser qualquer texto alfanumérico seguido por um espaço ou o final da string.

Executar o teste de linha de comando acima gera ...

()(link|label label)( )(link)( @tag more text)()()

Mas eu preciso que isso ceda ...

()(link|label label)( )(link)( )(tag)(more text)

Eu tentei várias strings de regex como "[][][][]|@[[:alnum:]]*" , o que elimina a palavra inteira e produz ...

()(link|label label)( )(link)( )( more text)()

e "[][][][]|@" que produz ...

()(link|label label)( )(link)( )(tag more text)()

Alguma idéia?

    
por DocSalvager 15.01.2014 / 19:35

3 respostas

0

Solução implementada

Esta é, na verdade, uma implementação da resposta de glenn com a adição da função definida pelo usuário stringSplit() para usar em vez da função Gawk 3.1.6 builtin split() que não suporta o quarto argumento opcional ( [seps] , uma matriz para armazenar os separadores) que precisamos. O Gawk 3.1.6 faz apoiar o terceiro argumento opcional de propósito similar a match() necessário, mas [seps] não está disponível até o Gawk 4.0.0.

# stringSplit(str,fld,rx,[sep])
#     Split string on regex delimeter preserving regex-seperators. Gawk 3.1.6
#     equivalent to builtin split() function of later versions which add
#     support for an optional 4th argument, ([seps]), an array to hold the
#     evaluated regular-expressions.
# Arguments:
#     str
#       string to split
#     fld
#       array of the resulting fields
#     rx
#       regular expression (regex) to split on
#     [sep]
#       optional array of seperator strings matching the regex
# Revised:
#     20140117 docsalvage
#
function stringSplit(str,fld,rx,sep,    searchstr,searchndx,match1,matchn,matches) {
  searchstr = str                     # copy of str to use in while() loop
  searchndx = match(searchstr, rx)    # index in searchstr where rx(regex) found
  match1    = searchndx               # preserve result of first match attempt
  matchn    = 1                       # match number (index in array of matches)
  matches   = 0                       # number of matches returned by split()
  #
  while (RLENGTH > 0) {               # more reliable than while(searchndx > 0)
    # save match
    sep[matchn] = substr(searchstr, searchndx, RLENGTH)
    #
    # match() only searches from beginning so give it just remainder of str
    searchstr   = substr(searchstr, searchndx + RLENGTH)
    #
    # printf("sep[%2d]: %s, searchndx: %2d, RLENGTH: %2d, searchstr: %s\n", matchn, sep[matchn], searchndx, RLENGTH, searchstr)
    #
    # search for next rx
    searchndx = match(searchstr, rx)
    matchn = matchn + 1
  }
  #
  if (match1)  matches = split(str,fld,rx)
  #
  return matches
}

BEGIN {
  print
  print "Test of:"
  print "  stringSplit()"
  print
  #
  str = "[[link|label label]][[link]] @tag more text some text with @anothertag and [[another|link]]"
  rx  = "[][][][]|@[[:alnum:]]+"
  #
  # fld - array of fields
  # sep - array of seperators
  #
  tags = 0
  matches = stringSplit(str,fld,rx,sep)
  #
  # arrayDebug("fld",fld)
  # arrayDebug("sep",sep)
  # print
  #
  print "Results:"
  printf "  "
  # per glenn jackman answer at
  #   http://unix.stackexchange.com/questions/109491/the-ere-regex-to-split-string-between-a-delimiter-and-end-of-word
  for (i=1; i<=matches; i++) {
    printf "(%s)", fld[i]
    if (match(sep[i], /^@(.+)/, m))  { printf "(%s)", m[1]; ++tags }
  }
  #
  print
  print
  print "Summary:"
  printf("  %d matches + %d tags = %d printed using regex(rx): %s\n  on string(str): %s\n", matches, tags, matches + tags, rx, str)
  print
}
    
por 17.01.2014 / 14:47
4

Eu não acho que você possa fazer isso em um único regex, mas como você está usando o gawk, você pode usar algumas extensões do gawk:

awk '{
    n = split($0, a, /\[\[|\]\]|@[[:alnum:]]+/, s)
    for (i=1; i<=n; i++) {
        printf "(%s)", a[i]
        if (match(s[i], /^@(.+)/, m))
            printf "(%s)", m[1]
    }
    print ""
}' <<END
[[link|label label]] [[link]] @tag more text
some text with @anothertag and [[another|link]]
END
()(link|label label)( )(link)( )(tag)( more text)
(some text with )(anothertag)( and )(another|link)()
    
por 15.01.2014 / 21:03
1

Isso é feio e horrível, mas fornece a saída desejada:

$ echo '[[link|label label]] [[link]] @tag more text' | 
 awk -vFS="[\\[\\] @]" '{
  OFS=":"; 
  printf "\n(" $1 ")(" $3" "$4 ")(" $5 ")(" $9 ")(" $10 ")(" $13 ")("; 
  rest=$14;
  for(i=15;i<=NF;i++){rest=rest" "$(i)}
  printf "%s)\n", rest;

 }'
()(link|label label)()(link)()(tag)(more text)

O truque é definir o separador de campo como% de [ , ] , @ ou (espaço). Se você puder fazer isso dentro do seu programa, ele deve fornecer a saída desejada.

    
por 15.01.2014 / 20:43