Perl regex não-ganancioso correspondendo mais do que deveria

2

Eu tenho o seguinte texto do qual preciso remover alguns wdiff output.

text='Иса Мәсіхтің елшісі Петірден [-(-] осы күнәкар дүниеде [-)-] жат жерлік болып, Понти, Ғалатия, [-Қападоқия, Азия және Бітүния аймақтарында шашыраған [ сенушілерге дұғай сәлем ].-] {+Қападоқия… https://t.co/.......... [Петірдің 1 1:1-5]+}'

Estou tentando remover um bloco de texto [- -] com o perl regex% não-ganancioso\[-.*?-\], mas também está correspondendo aos blocos anteriores:

$ perl -pe 's|\[-.*?-\] {\+(\S+… https://t.co/.*)\+}||' <<<"$text"
Иса Мәсіхтің елшісі Петірден Қападоқия… https://t.co/.......... [Петірдің 1 1:1-5]

Resultado esperado:

$ perl -pe 's|\[-.*?-\] {\+(\S+… https://t.co/.*)\+}||' <<<"$text"
Иса Мәсіхтің елшісі Петірден [-(-] осы күнәкар дүниеде [-)-] жат жерлік болып, Понти, Ғалатия, Қападоқия… https://t.co/.......... [Петірдің 1 1:1-5]
    
por Teresa e Junior 10.04.2015 / 06:51

2 respostas

2

Eu simplifiquei sua string de entrada para qABxBCzABxBCDEFw , onde

A represents [
B represents -
C represents ]
D represents {\+
E represents the text between the +s (including the URL)
F represents \+}
Lower case letters represent everything else.

Então, aqui estão alguns comandos substitutos executados contra a entrada:

                                  Command                          Output
0. Input text:                                                     qABxBCzABxBCDEFw
1. Non-greedy:                   's|AB.*?BCD(E)F||'              qEw
2. Greedy:                       's|AB.*BCD(E)F||'               qEw
3. Restricted Non-greedy:        's|AB[^B]*?BCD(E)F||'           qABxBCzEw
4. Restricted Greedy:            's|AB[^B]*BCD(E)F||'            qABxBCzEw
5. Constrained Non-greedy:       's|(.*)AB.*?BCD(E)F||'        qABxBCzEw
6. Constrained Greedy:           's|(.*)AB.*BCD(E)F||'         qABxBCzEw

O comando 1 é o que você tentou. O comando 2 é a mesma coisa, mas não é não-ganancioso. Como você sabe, eles produzem o mesmo resultado.

Parece-me que não-greedy se aplica apenas ao comprimento do texto correspondente por algo como .* . Não afeta o ponto de partida. As correspondências de regex sempre começam assim que podem. Então, quando você diz AB.*?BC (ou seja, \[-.*?-\] ), está igualando o primeiro [- na linha. Então, você espera, ele está combinando com a string mais curta possível de qualquer caractere que termine com -] . Você pode esperar que isso seja [-(-] . Mas olhe mais de perto: o regex é AB.*?BCD(E)F , por isso deve coincidir com a menor cadeia possível de qualquer caractere que termine com -] {+ . Isso força a consumir tudo quase até a URL.

Eu escrevi quatro comandos alternativos que parecem fazer o que você quer. As pesquisas "restritas" (3 e 4), não para AB.*BC , mas para AB[^B]*BC ; em palavras, ABBC sem B s no “…”. No seu caso, isso significa [--] sem - s no “…”. Os "restritos" (5 e 6) forçam a partida AB.*BC a começar tão tarde quanto possível, colocando um .* ganancioso na frente deles. Acontece que não importa se você faz a parte AB.*BC como ganancioso ou não-ganancioso nestes, também.

    
por 10.04.2015 / 09:03
2

Você precisa usar uma consulta negativa :

perl -pe 's|\[-((?!-\]).)*-\] {\+(\S+… https://t.co/.*)\+}||' <<<$text

O problema é a primeira ocorrência de [- correspondências. Então, a falta de ganância do padrão não produz o efeito desejado, não importa o quão não-ganancioso ele seja. Com um lookaround negativo, você pode combinar everthing, exceto da string -] , então, ele corresponde apenas à ocorrência antes da parte {+...+} .

    
por 10.04.2015 / 08:50