เหตุใด Line Feed จึงถูกแปลงเป็นอักขระ Null ภายในรีจิสเตอร์การค้นหาและเป็น Carriage Return บนบรรทัดคำสั่ง


12

ถ้าฉันมีข้อความต่อไปนี้:

foo
bar

ฉันเลือกและคัดลอก
ตอนนี้ข้อความถูกเก็บไว้ในการลงทะเบียนที่ไม่มีชื่อ"และนี่คือเนื้อหา (ผลลัพธ์ของ:reg "):

""   foo^Jbar^J

ตามแผนภูมินี้ดูเหมือนว่า^Jเครื่องหมายรูปหมวกสำหรับตัวดึงข้อมูลบรรทัด

หากฉันต้องการทำซ้ำทะเบียนที่ไม่มีชื่อในการaลงทะเบียนโดยพิมพ์: :let @a = @"
นี่คือเนื้อหา (output of :reg a):

"a   foo^Jbar^J

มันไม่เปลี่ยนแปลง

ถ้าตอนนี้ฉันทำซ้ำในทะเบียนการค้นหาโดยพิมพ์:let @/ = @"นี่คือเนื้อหา (ผลลัพธ์ของ:reg /):

"/   foo^@bar^@

ตามแผนภูมิก่อนหน้านี้ดูเหมือนว่า^@เป็นเครื่องหมายรูปหมวกสำหรับอักขระ Null
เหตุใด Line Feed จึงถูกแปลงเป็นอักขระ Null ภายในรีจิสเตอร์การค้นหาโดยอัตโนมัติ (แต่ไม่ใช่aรีจิสเตอร์)

ถ้าฉันแทรกการลงทะเบียนที่ไม่มีชื่อในบรรทัดคำสั่ง (หรือในการค้นหาหลังจาก/) โดยพิมพ์:<C-R>"นี่คือสิ่งที่ถูกแทรก:

:foo^Mbar^M

อีกครั้งตามแผนภูมิล่าสุด^Mดูเหมือนจะเป็นเครื่องหมายรูปหมวกสำหรับ Carriage Return
เหตุใด Line Feed จึงถูกแปลงเป็น Carriage Return บนบรรทัดคำสั่งโดยอัตโนมัติ

แก้ไข :

โดยปกติคุณสามารถแทรกอักขระควบคุมตามตัวอักษรโดยพิมพ์:
<C-V><C-{character in caret notation}>

ตัวอย่างเช่นคุณสามารถแทรกตัวอักษรโดยการพิมพ์<C-R> คุณสามารถทำได้เพื่อให้ดูเหมือนตัวควบคุมใด ๆ แต่ฉันพบว่าฉันไม่สามารถแทรกตัวอักษร LF ภายในบัฟเฟอร์หรือในบรรทัดคำสั่งเพราะถ้าฉันพิมพ์: มันแทรกอักขระ null แทน เป็นเพราะเหตุผลเดียวกันที่ LF ถูกแปลงเป็น NUL ภายในทะเบียนการค้นหาหรือไม่<C-V><C-R>

<C-V><C-J>^@^J

แก้ไข 2 :

ใน:h key-notationเราสามารถอ่านสิ่งนี้:

<Nul>       zero            CTRL-@    0 (stored as 10) <Nul>
<NL>        linefeed        CTRL-J   10 (used for <Nul>)

stored as 10ส่วนหนึ่งในบรรทัดแรกและused for <Nul>ในบรรทัดที่สองอาจบ่งชี้ว่ามีการเรียงลำดับของการทับซ้อนระหว่าง LF และ NUL บางและที่พวกเขาอาจจะตีความว่าเป็นสิ่งเดียวกัน แต่พวกเขาไม่สามารถเป็นสิ่งเดียวกันเพราะหลังจากดำเนินการคำสั่งก่อนหน้านี้:let @/ = @"ถ้าฉันพิมพ์nในโหมดปกติเพื่อไปยังที่เกิดขึ้นต่อไปของ 2 บรรทัดfooและbarแทนที่จะได้รับการจับคู่ที่เป็นบวกฉันมีข้อความแสดงข้อผิดพลาดต่อไปนี้:

E486: Pattern not found: foo^@bar^@

นอกจากลิงค์นี้จะอธิบายว่า NUL หมายถึงจุดสิ้นสุดของสตริงในขณะที่ LF แสดงถึงจุดสิ้นสุดของบรรทัดในไฟล์ข้อความ

และถ้า NUL เป็นstored as 10อย่างที่บอกไว้ซึ่งเป็นรหัสเดียวกับ LF, Vim สามารถสร้างความแตกต่างระหว่าง 2 ได้อย่างไร?

แก้ไข 3 :

บางทีรหัส LF และ NUL อาจมีรหัสทศนิยมเหมือนกัน10ตามความช่วยเหลือ และเสียงเรียกเข้าทำให้ความแตกต่างระหว่าง 2 ต้องขอบคุณบริบท ถ้ามันตรงกับตัวละครที่มีรหัสทศนิยมอยู่10ในบัฟเฟอร์หรือการลงทะเบียนใด ๆ ยกเว้นการค้นหาและคำสั่งการลงทะเบียนก็ตีความว่ามันเป็น LF
แต่ใน search register ( :reg /) มันตีความว่าเป็น NUL เพราะในบริบทของการค้นหา Vim จะค้นหาเฉพาะสตริงที่แนวคิดของend of line in a fileไม่สมเหตุสมผลเนื่องจากสตริงไม่ใช่ไฟล์ (ซึ่งแปลกเพราะคุณสามารถ ยังคงใช้อะตอม\nในรูปแบบการค้นหา แต่อาจเป็นเพียงคุณลักษณะของโปรแกรม regex หรือไม่) ดังนั้นจึงตีความโดยอัตโนมัติ10ว่าเป็น NUL เพราะเป็นแนวคิดที่ใกล้ที่สุด ( end of stringend of line)

และในทำนองเดียวกันบนบรรทัดคำสั่ง / การลงทะเบียนคำสั่ง ( :reg :) มันตีความรหัส10เป็น CR เพราะแนวคิดของend of line in a fileไม่เหมาะสมที่นี่ แนวคิดที่ใกล้ที่สุดคือend of commandเพื่อให้ตีความเป็นกลุ่ม10เป็น CR เพราะชนEnterเป็นวิธีที่จะสิ้นสุด / รันคำสั่งและ CR เป็นเช่นเดียวกับการกดปุ่มEnterตั้งแต่เมื่อคุณใส่หนึ่งตัวอักษรด้วย<C-V><Enter>, ^Mจะปรากฏ

บางทีการตีความของตัวละครที่มีรหัสคือ10การเปลี่ยนแปลงตามบริบท:

  • จุดสิ้นสุดของบรรทัดในบัฟเฟอร์ ( ^J)
  • จุดสิ้นสุดของสตริงในการค้นหา ( ^@)
  • สิ้นสุดคำสั่งบนบรรทัดคำสั่ง ( ^M)

2
บางครั้งการเกิดขึ้นของNULL ตัวละครที่ไม่คาดคิดเกิดจากฟังก์ชั่น C พื้นฐานที่จัดการกับสตริง นี้คำอธิบายวิธี C กระบวนการสตริงที่คุณเชื่อมโยงกับอธิบายว่าภายใน C delimits NULLสตริงกับ NULLเกิดขึ้นน้อยมากในข้อความที่ทำให้ตัวละครดีสำหรับวัตถุประสงค์นี้ ผลที่ตามมาก็คือหากโปรแกรม C (vim) พยายามส่งสตริง "ว่าง" ลงในฟังก์ชัน C ภายใน
the_velour_fog

2
เช่นsomeFunction(arg1, "")ที่ arg 2 คือ"" ie "รายการระหว่างเครื่องหมายคำพูดซึ่งไม่มีอะไรแท้จริง -" ว่าง "NULL สามารถปรากฏขึ้นได้เพราะมันเป็น" เพิ่ม "โดยการใช้งาน C พื้นฐานตามที่มันคั่นสตริงฉันไม่ทราบ คุณจะตรวจสอบสิ่งนี้ได้อย่างไร - แต่มันเป็นสาเหตุที่เป็นไปได้ในใจ
the_velour_fog

1
เห็นแล้วยังอภิปรายใน\rและ\n:substituteความแตกต่างใน
jamessan

คำตอบ:


4

ก่อนอื่นขอบคุณสำหรับการโพสต์ที่ครอบคลุมและมีน้ำใจ

หลังจากการทดสอบฉันได้ข้อสรุปนี้:

  1. อักขระควบคุมจะแสดงขึ้นโดยใช้เครื่องหมายรูปหมวก: ^Mสำหรับ<CR>(carriage return) และ^Jสำหรับ<LF>(feed line) ในบัฟเฟอร์<EOL>(end-of-line) จะแสดงเป็นบรรทัดหน้าจอใหม่และป้อนข้อมูลด้วยปุ่ม Enter <EOL>ขึ้นอยู่กับรูปแบบไฟล์ของบัฟเฟอร์: <EOL> = <CR>|<LF>|<CR><LF>สำหรับmac|unix|dosตามลำดับ

  2. เมื่อแก้ไขบัฟเฟอร์รูปแบบไฟล์จะถูกตั้งค่าเสมอ ในการเปลี่ยนรูปแบบไฟล์ของบัฟเฟอร์ที่เปิดคุณสามารถใช้คำสั่งต่อไปนี้ที่แปลง<EOL>:

    :set f[ile]f[ormat]=mac|unix|dos
    

    นอกเหนือไปจากการแปลง<EOL>คำสั่งนี้จะแปลง<LF>ไป<CR>เมื่อมีการเปลี่ยนรูปแบบไฟล์จากmacไปunix|dosและตรงกันข้าม<CR>ไป<LF>เมื่อมีการเปลี่ยนรูปแบบไฟล์จากไปunix|dos macหากต้องการดูไบต์ที่แท้จริงของบัฟเฟอร์คุณสามารถใช้คำสั่งต่อไปนี้ที่แปลงการแสดงข้อความของบัฟเฟอร์เป็นการแสดงฐานสิบหกโดยใช้ตัวแก้ไขเลขฐานสิบหกที่สะดวกสบาย xxd:

    :%!xxd
    
  3. ในการลงทะเบียน (แสดงให้เห็นว่ามีคำสั่ง:reg[isters]หรือ:di[splay]) <EOL>มักจะแสดงเป็น^J( แต่ไม่ใช่ทั้งหมด^Jมี<EOL>) โดยไม่คำนึงถึงรูปแบบไฟล์ของบัฟเฟอร์ อย่างไรก็ตาม<EOL>จะถูกเก็บไว้ตามที่ควร เพื่อให้สามารถแยกแยะความจริงทางสายตา^J(นั่นคือ<LF>) จากสิ่งอื่น ๆ^J(นั่นคือ<EOL>) ในการลงทะเบียนคุณสามารถใช้คำสั่งต่อไปนี้ที่แสดงค่าเลขฐานสิบหกแทนสัญรูปคาเร็ตของตัวควบคุมที่แตกต่างจาก<EOL>:

    :set d[ispla]y=uhex
    
  4. ในรูปแบบการค้นหาและสตริงการแทนที่:

    \r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
    \n = <EOL>
    
  5. ทุกที่:

    <C-V><C-M>|<C-V><EOL> = newline different from <EOL>
    <C-V><C-J> = <NUL>
    

    นี้แสดงให้เห็นว่าเมื่อรูปแบบไฟล์คือdosมันเป็นไปไม่ได้ที่จะป้อนข้อมูล<LF>ตั้งแต่และ<EOL> = <CR><LF><C-V><C-M>|<C-V><EOL> = <CR>

  6. ในสตริงการทดแทน:

    • ขึ้นบรรทัดใหม่ที่แตกต่างจาก<EOL>ถูกตีความว่าเป็น<EOL>;

    • <EOL>จะตีความ<NUL>เป็น

    ดังนั้นตาม 4. :%s[ubstitute]/\r/\r/gแทนที่ทุกที่แตกต่างกันขึ้นบรรทัดใหม่จาก<EOL>ในบัฟเฟอร์ที่มี<EOL>ในขณะที่:%s[ubstitute]/\n/\n/gแทนที่ทุกในบัฟเฟอร์ด้วย<EOL><NUL>

  7. ในการลงทะเบียนการค้นหา/และคำสั่งการลงทะเบียน:, <EOL>มีการแปลงไป

    • ขึ้นบรรทัดใหม่แตกต่างจาก<EOL>เมื่อแทรกจากการลงทะเบียนด้วย/<C-R>{register}หรือ:<C-R>{register}ตามลำดับ;

    • <NUL>เมื่อแทรกจากการลงทะเบียนด้วย:let @/=@{register}หรือ:let @:=@{register}ตามลำดับ

  8. ในบัฟเฟอร์ขึ้นบรรทัดใหม่ที่แตกต่างจาก<EOL>ที่มีการแปลงไปเมื่อแทรกจากการลงทะเบียนโดยใช้<EOL>i<C-R>{register}

เหตุใด Line Feed จึงถูกแปลงเป็นอักขระ Null ภายในรีจิสเตอร์การค้นหาและเป็น Carriage Return บนบรรทัดคำสั่ง

ก่อนที่จะคัดลอก<LF>จากการลงทะเบียนชื่อ"ที่จะลงทะเบียนอื่น ๆ ที่คุณต้องใส่และนำไปใช้ในการลงทะเบียน<LF> "หากรูปแบบไฟล์คือunixคุณสามารถทำได้โดยใช้yyบรรทัดว่าง หากรูปแบบไฟล์คือmacคุณสามารถทำได้โดยใช้i<C-V><C-M><Esc>yl; หากรูปแบบไฟล์คือdosคุณไม่สามารถป้อน<LF>(cf. 5. )

ตอนนี้คำสั่งของคุณผิดบางส่วนตั้งแต่

  • คุณไม่ได้ใช้วิธีการเดียวกันสำหรับการคัดลอก<LF>จากการลงทะเบียน"เข้าสู่การลงทะเบียนการค้นหาและลงทะเบียนคำสั่ง/ :คุณสามารถใช้:let @/=@"สำหรับการคัดลอกลงในการลงทะเบียน/และสำหรับการคัดลอกลงในการลงทะเบียน:<C-R>" :การใช้/<C-R>"และ:<C-R>"ตามลำดับจะให้ผลลัพธ์เดียวกัน ( <CR>) ในทั้งสองกรณี

  • แปลงของใช้สถานที่ที่มีสองวิธีที่แตกต่างกันสำเนาของคุณเกิดขึ้นได้ก็ต่อเมื่อรูปแบบไฟล์เป็น<LF> unixถ้ามันเป็นmac, <LF>จะไม่แปลงเมื่อคัดลอกไปลงทะเบียน/หรือการลงทะเบียน:และถ้ามันเป็นคุณไม่สามารถแม้กระทั่งการป้อนข้อมูลdos<LF>

ข้อความที่ถูกต้องถูกกำหนดโดย 7 แต่ฉันไม่รู้เหตุผลเบื้องหลังจริงๆ


ทำไมเรื่องนี้ถึงยากนักที่จะเข้าใจ ... ฉันได้ทำการวิจัยผ่านหลายข้อความเกี่ยวกับ SO และ vim-SE และความช่วยเหลือของ vim แต่ไม่สอดคล้องกันอย่างสมบูรณ์และยังคงสับสน
Violapterin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.