ความแตกต่างระหว่าง '\ zs' และ '\ @ <=' อะตอมใน Vim regex คืออะไร


11

นี่คือสิ่งที่ฉันได้รับจากเอกสาร: \zs"จะเริ่มต้นส่วนไฮไลต์" หลังจากจับคู่ regex ก่อนหน้าและ\@<="จะเริ่มต้นเป็นส่วนหนึ่งที่ไฮไลต์" หลังจากจับคู่ก่อนหน้านี้อะตอม แต่ฉันไม่เข้าใจรายละเอียดปลีกย่อยของเรื่องนี้ดังนั้นทุกคนสามารถอธิบายได้ว่าพวกเขามีความลึกมากกว่านี้อย่างไร

นี่คือสิ่งที่ทำให้ฉันอยากรู้: ถ้าฉันวิ่ง

/\_s\zsnnoremap

เช่นเลือกnnoremapนำหน้าด้วยช่องว่างหรือจุดเริ่มต้นของบรรทัด (เช่น newline จากบรรทัดก่อนหน้าดังนั้น\_ก่อนหน้านั้นs) จากนั้นเรียกใช้gnเพื่อเข้าสู่โหมดภาพและเลือกการแข่งขันนัดถัดไปด้วยเหตุผลบางประการเฉพาะคอลัมน์แรก (เช่น ครั้งแรกnในnnoremap) ถูกเลือก - แม้จะมีความจริงที่ว่าทั้งnnoremapคำที่ไฮไลต์ที่มีการ:hlsearchเปิด

อย่างไรก็ตามถ้าฉันเรียกใช้การค้นหาแทน

/\_s\@<=nnoremap

จากนั้นลองgnเลือกทั้งหมดnnoremapอย่างถูกต้อง เกิดอะไรขึ้นที่นี่? ฉัน (ฉันกล้าพูด) พบข้อบกพร่องที่คลุมเครือบ้างไหม


ฉันคิดว่ามันอยู่ใน:h patternsความทรงจำของฉัน แต่แนะนำว่า regex ประกอบด้วยอะตอมถ้าช่วยอธิบายความแตกต่าง
D. Ben Knoble

คำตอบ:


15

ดูเหมือนว่าคุณจะพบข้อบกพร่องที่ชัดเจน ฉันได้ติดตั้งgntextobject ย้อนกลับไปในปี 2012 สำหรับ Vim 7.3 บางอย่างแล้ว มันใช้งานได้ตามวิธีต่อไปนี้:

1) ค้นหาย้อนหลังสำหรับการจับคู่สุดท้ายของนิพจน์ทั่วไปปัจจุบัน

2) มันค้นหาไปข้างหน้าสำหรับการจับคู่ต่อไปของการแสดงออกปกติในปัจจุบัน

สิ่งนี้ควรชัดเจนว่าเคอร์เซอร์จะเริ่มต้นในนัดถัดไปแม้ว่าจะมีเมื่อเริ่มต้นของ 1) ในที่สุด

3) มันค้นหาจุดสิ้นสุดของนิพจน์ปกติปัจจุบัน และวางเคอร์เซอร์ไว้ที่นั่น

ตอนนี้สิ่งที่เกิดขึ้นที่นี่คือการค้นหาจุดสิ้นสุดของการจับคู่ปัจจุบันล้อมรอบและย้ายกลับไปที่จุดสิ้นสุดของการแข่งขันก่อนหน้า (เนื่องจากwrapscanถูกตั้งค่าไว้แล้วหลังจากถูกปิดใช้งานสำหรับ 1) จากนั้นตั้งค่าตัวทำเครื่องหมายภาพเป็นพื้นที่ตั้งแต่เริ่มต้น (จุดสิ้นสุดของจุดที่ 2) และพื้นที่ที่ถูกย้ายไปตามรายการค้นหาถัดไป 3)

ฉันจะดูปัญหาอย่างละเอียดและอาจส่ง patch สำหรับ Vim ในภายหลัง

[อัพเดท 22.05.2018]ฉันได้เขียนและส่งตัวปะแก้เพื่อแก้ไขปัญหานี้

[Update2 22.05.2018] และได้รับการรวมเข้าด้วยกันเป็นระดับแพทช์8.1.0018

[อัพเดต 22.10.2019] ในฐานะของ Vim patch 8.1.629ขั้นตอนที่สามจะไม่ดำเนินการอีกต่อไป แทนเป็นกลุ่มในขณะนี้สามารถกำหนดจุดสิ้นสุดของการแข่งขันเมื่อค้นหาจุดเริ่มต้นของการแข่งขัน (ขั้นตอนที่ 2)


8

คริสเตียนได้ที่สมบูรณ์คำถามของพฤติกรรมที่รถของgnแต่ยังคงมีความแตกต่างพื้นฐานระหว่างและ\zs \@<=สิ่งที่ใหญ่ที่สุดคือ\@<=ปรับเปลี่ยนอะตอมก่อนหน้าในขณะที่\zsเป็นอะตอมในตัวของมันเอง

พิจารณา:

Xnnoremap

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

การแข่งขัน Regex 1 นับตั้งแต่การ\%1cแข่งขันคอลัมน์ 1 และมี X ตรงนั้น \zsทำให้การแข่งขันเริ่มต้นที่ตำแหน่งหลัง X เท่านั้น

อย่างไรก็ตาม Regex 2 ไม่ตรงกันเนื่องจากแม้ว่า\%1cตรงกับคอลัมน์แรกX\@<=จะมีความกว้างเป็นศูนย์ (ดังที่กล่าวไว้ในเอกสารประกอบ) และnnoremapเริ่มที่คอลัมน์ 2 ไม่มีอะไรที่จะทำให้เกิดความแตกต่างของตำแหน่งระหว่างคอลัมน์ 1 และ 2

การแข่งขัน Regex 3 นับตั้งแต่nnoremapเริ่มต้นที่คอลัมน์ 2


1
ฉันไม่คิดว่า regex 2 ล้มเหลวเนื่องจากไม่มีสิ่งใดที่ทำให้เกิดความแตกต่างของตำแหน่งระหว่างคอลัมน์ 1 และ 2 หากนั่นเป็นปัญหาการลบออกnnoremapจาก regex จะทำให้เกิดการแข่งขัน แต่ regex ยังคงล้มเหลวแม้ไม่มี ฉันคิดว่ามันล้มเหลวเพราะ\%1cX\@<=เป็นการแสดงออกถึงตำแหน่งที่ไม่มีอยู่จริง \%1cจับคู่ตำแหน่งที่คอลัมน์ 1 และX\@<=ขอให้อักขระXจับคู่ก่อนหน้านั้น แต่จะต้องไม่มีตัวอักษรใด ๆ อยู่ก่อนคอลัมน์แรก ซึ่งเป็นเหตุผลว่าถึงแม้ว่าคุณจะแทนที่Xด้วยจุด (ตัวอักษรใด ๆ ) regex \%1c.\@<=ยังคงล้มเหลว
user938271

4

\zsใช้กับนิพจน์ทั่วไปทั้งหมดและตั้งค่าอักขระถัดไปให้เป็นอักขระตัวแรกของการแข่งขันทั้งหมด สิ่งใดก่อนที่\zsจะไม่ถูกรวมเป็นส่วนหนึ่งของข้อความที่ตรงกัน

\@<=ในทางกลับกันจะมีผลกับอะตอมโดยตรงที่อยู่รอบ ๆ เท่านั้นทำให้คุณสามารถระบุว่าอะตอมถัดไปจะจับคู่ก็ต่อเมื่ออะตอมนั้นตามหลังอะตอมก่อนหน้า ตัวอย่างเช่นนิพจน์ทั่วไป:

\vbar.*(foo)@<=bar

จะตรงกับข้อความทั้งหมดระหว่างสองกรณีของbar(รวมถึงกรณีที่ตัวเอง) fooแต่ถ้าสองจะนำหน้าด้วย เช่นมันจะจับคู่:

barbazfoobar

แต่ไม่:

barbazbazbar

เนื่องจาก\@<=มีการแปลเป็นภาษาท้องถิ่นด้วยวิธีนี้คุณสามารถใช้\@<=หลายครั้งในการแสดงออกครั้งเดียว:

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

ต่อไปนี้จะตรงกับสามกรณีแต่ถ้าที่สองทั้งสองแต่ละนำหน้าด้วยbarfoo

เช่นได้รับข้อความ:

barfoobarbazfoobar
barfoobarbazbazbar
barbazbarbazfoobar

มันจะตรงกับบรรทัดแรกเท่านั้น


แต่คุณสามารถแลกเปลี่ยน lookbehind แรกที่มีเช่นนี้ควรทำงาน:\zs \vfoo\zsbar.*(foo)@<=bar
Karl Yngve Lervåg

@ KarlYngveLervågจุดที่ดี ฉันได้แก้ไขเพื่อให้เห็นความแตกต่างที่ชัดเจนและใช้ตัวอย่างที่\zsไม่สามารถทดแทนได้ทั้งหมด
รวย

ดังนั้นเพื่อความเข้าใจของฉัน\zsและ\zeสามารถถูกแทนที่ด้วยการดูรูปแบบ regex และพวกเขามีประสิทธิภาพมากขึ้นใช่มั้ย สาเหตุที่ทรงพลังมากขึ้นสามารถใช้งานได้มากกว่าหนึ่งครั้งและสามารถจัดกลุ่ม\(\)ได้ และยังเป็นเพราะพวกเขาทำงานเหมือน perl ดูรอบ ๆ regex มีอะไรผิดพลาด?
klaus

1
@klaus ฟังดูแล้วเหมาะกับฉัน (แม้ว่าฉันจะไม่มีความเชี่ยวชาญ) โปรดทราบว่าคุณควรใช้\zs/ \zeเมื่อสามารถทำได้เพราะเร็วกว่าการมองไปรอบ ๆ
Rich

เข้าใจ และ\zsและ\zeจะเห็นได้ชัดง่ายขึ้น ขอบคุณสำหรับคำอธิบาย
klaus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.