Como encontrar todas as correspondências para uma expressão regular em uma string

3

No POSIX awk e Gawk, respectivamente, como podemos encontrar todas as correspondências para uma expressão regular em uma string?

Mais especificamente, encontre todas as correspondências que são substituídas pela função gsub builtin, em termos de um dos dois objetivos a seguir:

  • encontre a posição e o comprimento de cada correspondência na string de destino e

  • encontre as correspondências somente como substrings da string de destino.

Alcançar o primeiro objetivo implica alcançar o segundo objetivo.

  1. No POSIX awk,

    Existe uma função incorporada que pode alcançar qualquer um dos dois Objetivos?

    A função match builtin encontra apenas a mais à esquerda e a mais longa jogo?

    Para alcançar o primeiro objetivo, é uma maneira correta de repetidamente aplique match ao sufixo da string de destino criada por encontrar cada partida e removendo a correspondência e o prefixo antes de a string de destino? É link correto implementação?

  2. Em Gawk,

    faz array após uma chamada patsplit(string, array, fieldpat, seps) armazenar os jogos conforme exigido no segundo objetivo? Pode o os locais da localização da partida podem ser encontrados em array e seps , com base nesse seps[i] é a string separadora entre array[i] e array[i+1] ?

Obrigado.

    
por Tim 18.07.2017 / 22:46

1 resposta

2

  1. In POSIX awk,
    Is there a builtin function which can achieve either of the two objectives?

Não. Você pode conseguir o mesmo efeito, mas não com uma única função interna.

Does the match builtin function only find the leftmost and longest match?

Sim. Expressões regulares em POSIX awk (e GNU awk ) são sempre gananciosas (ou seja, a correspondência mais longa sempre ganha).

To achieve the first objective, is it a correct way to repeatedly apply match to the suffix of the target string created by finding each match and removing the match and the prefix before it from the target string?

Sim, mas se você quiser 100% de compatibilidade com gsub() , os detalhes serão bem complicados.

Is https://gist.github.com/mllamazing/a40946fcf8211a503bed a correct implementation?

Principalmente, se você remover a linha do gsub . O diabo está nos detalhes: o código irá fazer um loop se regex for uma string vazia. O awk clássico não permitia regexps vazios, mas o IIRC nawk sim. Para corrigir isso, você poderia fazer algo assim:

function FindAllMatches(str, regex, match_arr) {

    ftotal = 0;
    ini = RSTART;
    leng = RLENGTH;

    delete match_arr;

    while (str != "" && match(str, regex) > 0) {
        match_arr[++ftotal] = substr(str, RSTART, RLENGTH)
        str = substr(str, RSTART + (RLENGTH ? RLENGTH : 1))
    }

    RSTART = ini;
    RLENGTH = leng;
}

Isso não é 100% compatível com gsub() , porque

$ echo 123 | awk '{ gsub("", "-") } 1'
-1-2-3-

enquanto a função acima encontra apenas 3 correspondências (ou seja, ela perde o jogo no final).

Você pode tentar isso:

function FindAllMatches(str, regex, match_arr) {

    ftotal = 0;
    ini = RSTART;
    leng = RLENGTH;

    delete match_arr;

    while (match(str, regex) > 0) {
        match_arr[++ftotal] = substr(str, RSTART, RLENGTH)
        if (str == "") break
        str = substr(str, RSTART + (RLENGTH ? RLENGTH : 1))
    }

    RSTART = ini;
    RLENGTH = leng;
}

Isso corrige o problema acima, mas quebra outros casos: se str = "123" e regex = "[1-9]*" a função encontrar duas ocorrências, 123 e a string vazia no final, enquanto gsub() encontrar apenas uma, 123 .

Pode haver outras diferenças semelhantes, que não posso me incomodar em caçar agora.

  1. In Gawk,

    does array after a call patsplit(string, array, fieldpat, seps) store the matches as required in the second objective?

Principalmente sim. No entanto, casos de canto relacionados a regexps podem ser inesperadamente sutis. Pode haver algumas diferenças, como acima.

Can the locations of the match location be found from array and seps, based on that seps[i] is the separator string between array[i] and array[i+1]?

Sim.

    
por 20.07.2017 / 08:28