Vim正規表現の「\ zs」と「\ @ <=」アトムの違いは何ですか?


11

これは私がドキュメントから得たものです。\zs前の正規表現\@<=に一致した後に「強調表示された部分を開始」し、前のアトムに一致した後に「強調表示された部分を開始」します。しかし、私はこれの微妙さを正確に理解していないので、誰がそれらが少し深く異なっているかを誰かが説明できますか?

これが私を不思議に思った理由です。

/\_s\zsnnoremap

つまり、nnoremap先頭にスペースまたは行頭(つまり、前の行からの改行、つまり\_前のs)を選択し、実行gnしてビジュアルモードに入り、何らかの理由最初の列のみ(つまり、最初の列(つまり最初の内は)選択されている-全体という事実にもかかわらず、言葉がされて強調して点灯します。nnnoremapnnoremap:hlsearch

ただし、代わりに検索を実行すると

/\_s\@<=nnoremap

を試してみてください。gn全体nnoremapが適切に選択されています。ここで何が起こっているのでしょうか?私は(あえて言う)いくつかのあいまいなバグを発見しましたか?


私はそう思います:h patternsが、私の記憶では、正規表現は原子で構成されていることを示唆しています。
D.ベンノーブル

回答:


15

これは確かに不明瞭なバグを見つけたようです。gn2012年にVim 7.3向けにtextobject を実装しました。基本的には次のように機能します。

1)現在の正規表現の最後の一致を後方検索します。

2)現在の正規表現の次の一致を前方検索します。

これにより、カーソルが次の一致の開始位置にあることが明らかになります。これは、1)の開始時にすでに存在していた場合でも同じです。 最後に

3)現在の正規表現の終わりを検索します。そこにカーソルを置きます。

ここで何が起こるかというと、現在のマッチの最後の検索が折り返され、前のマッチの最後に戻ります(wrapscan1で無効にされた後、既に設定されているため)。次に、ビジュアルマーカーを開始(ポイント2の終わり)からのエリアに設定し、エリアを次の検索項目3)によって移動します。

私は問題をより詳しく見ていき、おそらくVimのパッチを後で提出するでしょう。

[2018年5月22日更新]この動作を修正するパッチを書いて提出しました。

[Update2 22.05.2018] そして、パッチはパッチレベル8.1.0018としてマージされました

[2019年10月22日更新] Vimパッチ8.1.629以降、3番目のステップは実行されなくなりました。代わりに、Vimは試合の開始を見つけるときに、試合の終了を判断できるようになりました(ステップ2)。


8

クリスチャンはのバグのある動作の問題に完全に対処しましたがgn、との間には根本的な違いが\zsあり\@<=ます。最大のもの\@<=は前のアトムを変更します\zsが、iselfのアトムです。

検討してください:

Xnnoremap

\%1cX\zsnnoremap     (regex 1)
\%1cX\@<=nnoremap    (regex 2)
\%2cX\@<=nnoremap    (regex 3)

\%1c列1に一致し、そこにXがあるため、正規表現1が一致します。 \zsXの後の位置で試合が再開されるだけです。

ただし、Regex 2は一致しません。これは\%1c、最初の列と一致しますが、X\@<=(ドキュメントで説明されているように)幅がゼロでnnoremapあり、列2から始まるためです。列1と2の位置の違いを補うものはありません。

nnoremap列2 から始まって、正規表現3が一致します。


1
列1と2の間の位置の違いを補うものがないため、正規表現2が失敗するとは思いません。それが問題である場合nnoremap、正規表現から削除すると一致します。しかし、正規表現はそれがなくても失敗します。\%1cX\@<=存在できない立場を表現しているので失敗だと思います。\%1c列1の位置に一致し、その前に一致X\@<=する文字Xを要求します。ただし、最初の列の前に文字を置くことはできません。そのためX、ドット(任意の文字)に置き換えても、正規表現\%1c.\@<=は失敗します。
user938271

4

\zs正規表現全体に適用され、次の文字を一致全体の最初の文字に設定します。の前\zsは、一致するテキストの一部として含まれません。

\@<=一方、その周囲の原子にのみ影響を与え、次の原子が前の原子に続く場合にのみ一致するように指定できます。したがって、たとえば、正規表現:

\vbar.*(foo)@<=bar

bar(インスタンス自体を含む)の2つのインスタンス間のすべてのテキストに一致しますが、2番目のインスタンスの前にがある場合のみですfoo。つまり、次のように一致します。

barbazfoobar

だがしかし:

barbazbazbar

\@<=はこのようにローカライズされているため\@<=、1つの式で複数回使用することもできます。

\vbar.*(foo)@<=bar.*(foo)@<=bar

以下は、の3つのインスタンスに一致しますがbar、2番目の2 つのインスタンスの前にが付いている場合のみですfoo

すなわち、テキストが与えられます:

barfoobarbazfoobar
barfoobarbazbazbar
barbazbarbazfoobar

最初の行のみに一致します。


ただし、最初の後読みをと交換できます。\zsつまり、これも機能するはずです\vfoo\zsbar.*(foo)@<=bar
Karl YngveLervåg18年

@KarlYngveLervåg良い点。区別を明確にするために、また\zsまったく代替できない例を使用するために編集しました。
リッチ

だから、私の理解のために、\zsそして\ze見回す正規表現パターンに置き換えることができ、それらはより強力ですよね?より強力な原因は、複数回使用でき、とグループ化できます\(\)。また、Perlの正規表現のように動作するためです。何か間違っている?
クラウス

1
@klaus(私は専門家ではありませんが)それは私には大体正しいように聞こえます。ただし、可能な場合は\zs/ を使用\zeする必要があります。ルックアラウンドよりも高速であるためです。
リッチ

わかった。そして\zs\ze明らかにより直感的です。説明ありがとうございます。
クラウス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.