É o que recebo da documentação: \zs
"inicia a parte destacada" após corresponder ao regex anterior e \@<=
"inicia a parte destacada" após corresponder ao átomo anterior . Mas eu não entendo exatamente as sutilezas disso, então alguém pode explicar como elas diferem um pouco mais em profundidade?
Foi isso que me deixou curioso: se eu correr
/\_s\zsnnoremap
ou seja, selecione nnoremap
precedido por um espaço ou um início de linha (ou seja, a nova linha da linha anterior e, portanto, a \_
anterior s
) e depois corra gn
para entrar no Modo Visual e selecione visualmente a próxima correspondência, por algum motivo, apenas a primeira coluna (ou seja, o primeiro n
em nnoremap
) é selecionado - apesar do fato de que toda a nnoremap
palavra é realçada com :hlsearch
ligado.
No entanto, se eu executar a pesquisa
/\_s\@<=nnoremap
e tente gn
, o todo nnoremap
está selecionado corretamente. O que poderia estar acontecendo aqui? Eu (ouso dizer) descobri algum bug obscuro?
fonte
:h patterns
mas minha memória sugere que os regexs são compostos de átomos, se isso ajudar a explicar a diferença.Respostas:
Parece que você realmente encontrou um bug obscuro. Eu implementei o
gn
textobject em 2012 para o Vim 7.3. Basicamente, funciona da seguinte maneira:1) Ele pesquisa para trás a última correspondência da expressão regular atual.
2) Procura a próxima correspondência da expressão regular atual.
Isso deve deixar claro que o cursor estará no início da próxima partida, mesmo se já estivesse lá no início de 1).
Finalmente3) procura o final da expressão regular atual. e coloca o cursor lá.Agora, o que acontece aqui é que a busca pelo final da partida atual se aproxima e volta para o final da partida anterior (porque
wrapscan
já está definida, depois de ser desabilitada para 1). Em seguida, define o marcador Visual para a área desde o início (final do ponto 2) e a área movida para o próximo item de pesquisa 3).Examinarei mais de perto o problema e provavelmente enviará um patch para o Vim mais tarde.
[Atualização 22.05.2018] Eu escrevi e enviei um patch para corrigir esse comportamento.
[Atualização2 22.05.2018] E o patch foi mesclado como nível de patch 8.1.0018
[Atualização 22.10.2019] No patch 8.1.629 do Vim, a terceira etapa não é mais executada. Em vez disso, o Vim agora pode determinar o final da partida ao encontrar o início da partida (Etapa 2)
fonte
Christian abordou completamente a questão do comportamento de buggy de
gn
, mas ainda existem diferenças fundamentais entre\zs
e\@<=
. O maior ser\@<=
modifica um átomo anterior, enquanto\zs
é um átomo em si.Considerar:
O Regex 1 corresponde, pois
\%1c
corresponde à coluna 1 e existe um X lá.\zs
apenas faz com que a partida seja reiniciada em uma posição após o X.O Regex 2, no entanto, não corresponde, porque, embora
\%1c
corresponda à primeira coluna,X\@<=
tem largura zero (conforme mencionado na documentação) ennoremap
inicia na coluna 2. Não há nada para compensar a diferença de posição entre as colunas 1 e 2.O Regex 3 corresponde desde o
nnoremap
início na coluna 2.fonte
nnoremap
da regex produziria uma correspondência; mas o regex ainda falha mesmo sem. Eu acho que falha porque\%1cX\@<=
expressa uma posição que não pode existir.\%1c
corresponde à posição na coluna 1 eX\@<=
solicita que um personagemX
corresponda antes disso. Mas não pode haver nenhum caractere antes da primeira coluna. É por isso que, mesmo se você substituirX
por um ponto (qualquer caractere), a regex\%1c.\@<=
ainda falhará.\zs
aplica-se a toda a expressão regular e define o próximo caractere como o primeiro caractere de toda a correspondência. Qualquer coisa anterior ao\zs
não será incluída como parte do texto correspondente.\@<=
, por outro lado, afeta apenas os átomos diretamente ao seu redor, permitindo especificar que o próximo átomo corresponderá apenas se seguir o átomo anterior. Então, por exemplo, a expressão regular:Corresponderá todo o texto entre duas instâncias de
bar
(incluindo as próprias instâncias), mas apenas se a segunda for precedida porfoo
. ou seja, corresponderá:mas não:
Como
\@<=
é localizado dessa maneira, você pode até usar\@<=
várias vezes em uma única expressão:O seguinte corresponderá a três instâncias de
bar
, mas somente se as duas primeiras forem precedidas porfoo
.ou seja, dado o texto:
Ele corresponderá apenas à primeira linha.
fonte
\zs
, ou seja, isso também deve funcionar:\vfoo\zsbar.*(foo)@<=bar
.\zs
não podem ser substituídos.\zs
e\ze
pode ser substituído por olhar em torno de padrões regex, e eles são mais poderosos, certo? Causa mais poderosa: eles podem ser usados mais de uma vez e podem ser agrupados\(\)
. E também porque eles funcionam como o perl olha em volta do regex. Algo errado?\zs
/\ze
quando puder, porque é mais rápido do que olhar em volta.\zs
e\ze
são, obviamente, mais intuitiva. Obrigado pelas explicações.