จะแทนที่แต่ละนัดด้วยตัวนับที่เพิ่มขึ้นได้อย่างไร


14

ฉันต้องการค้นหาและแทนที่แต่ละรูปแบบที่แน่นอนด้วยตัวเลขทศนิยมซึ่งเริ่มต้นที่1และเพิ่มขึ้นทีละหนึ่งสำหรับแต่ละการแข่งขัน

ฉันสามารถค้นหาคำถามที่มีคำพูดในทำนองเดียวกันที่กลายเป็นว่าไม่เกี่ยวกับการเพิ่มจำนวนตัวนับ แต่แก้ไขการจับคู่แต่ละครั้งด้วยจำนวนเงินที่แน่นอน คำถามที่คล้ายกันอื่น ๆ เกี่ยวกับการแทรกหมายเลขบรรทัดมากกว่าตัวนับที่เพิ่มขึ้น

ตัวอย่างก่อน:

#1
#1.25
#1.5
#2

หลังจาก:

#1
#2
#3
#4

ข้อมูลจริงของฉันมีข้อความมากขึ้นทุกสิ่งที่ฉันต้องการหมายเลขใหม่


2
หากคุณมีperldoคุณสามารถใช้:%perldo s/#\K\d+(\.\d+)?/++$i/ge
Sundeep

@Sundeep: ฉันควรจะกล่าวถึงฉันในวานิลลา Windows 10 ขอโทษ!
hippietrail

คำตอบ:


15

คุณต้องทดแทนด้วยสถานะ ฉันจำได้ว่าได้ให้โซลูชันที่สมบูรณ์ (/ หลายรายการ) สำหรับปัญหาประเภทนี้ใน SO

นี่เป็นอีกวิธีในการดำเนินการ (1) ตอนนี้ฉันจะดำเนินการใน 2 ขั้นตอน:

  • ตัวแปรรายการหุ่นที่ฉันต้องการสำหรับเคล็ดลับสกปรกและซับซ้อนที่ฉันจะจ้าง
  • การแทนที่ที่ฉันแทรก len ของอาร์เรย์จำลองนี้ที่ฉันเติมในแต่ละเหตุการณ์ที่ตรงกัน

ซึ่งจะช่วยให้:

:let t=[]
:%s/#\zs\d\+\(\.\d\+\)\=\ze/\=len(add(t,1))/g

หากคุณไม่คุ้นเคยกับกลุ่ม regexes ฉันจะใช้:h /\zsและ\zeระบุรูปแบบย่อยที่ฉันกำลังจับคู่อยู่จากนั้นฉันจับคู่ชุดตัวเลขที่อาจตามด้วยจุดและตัวเลขอื่น ๆ นี่ไม่เหมาะสำหรับเลขทศนิยมใด ๆ แต่นี่ก็เพียงพอแล้ว

หมายเหตุ: คุณจะต้องสรุปในฟังก์ชั่นคู่ + คำสั่งสำหรับอินเตอร์เฟซที่เรียบง่าย อีกครั้งมีตัวอย่างในดังนั้น / กลุ่ม ( ที่นี่ , ที่นี่ , ที่นี่ ) ปัจจุบันฉันรู้มากพอที่จะเป็นกลุ่มที่จะได้ดูแลเกี่ยวกับการตัดเคล็ดลับนี้ลงในคำสั่ง แน่นอนฉันจะสามารถเขียนคำสั่งนี้ได้ในการลองครั้งแรกในขณะที่ฉันจะใช้เวลาหลายนาทีในการจดจำชื่อของคำสั่ง


(1) วัตถุประสงค์คือเพื่อให้สามารถรักษาสถานะในระหว่างการแทนที่และเพื่อแทนที่เหตุการณ์ปัจจุบันด้วยสิ่งที่ขึ้นอยู่กับสถานะปัจจุบัน

ขอขอบคุณที่:s\=เราสามารถแทรกสิ่งที่เกิดจากการคำนวณ

ยังคงเป็นปัญหาของรัฐ เราอาจกำหนดฟังก์ชันที่จัดการสถานะภายนอกหรือเราอัพเดตสถานะภายนอก ใน C (และภาษาที่เกี่ยวข้อง) เราอาจจะมีบางสิ่งบางอย่างที่ใช้เหมือนหรือlength++ length+=1น่าเสียดายที่ในกลุ่มสคริปต์+=ไม่สามารถใช้งานได้นอกกรอบ จะต้องมีการใช้ทั้งที่มีหรือ:set :letซึ่งหมายความว่าจะ:let length+=1เป็นการเพิ่มจำนวน แต่จะไม่ส่งคืนสิ่งใด :s/pattern/\=(length+=1)เราไม่สามารถเขียน เราต้องการสิ่งอื่น

เราต้องการฟังก์ชั่นการกลายพันธุ์ ฟังก์ชั่นคือการเปลี่ยนแปลงอินพุตของพวกเขา เรามีsetreg(), map(), add()และอาจจะมากขึ้น เริ่มจากพวกเขากันก่อน

  • setreg()เปลี่ยนแปลงการลงทะเบียน สมบูรณ์ เราสามารถเขียนได้setreg('a',@a+1)ในโซลูชันของ @Doktor OSwaldo และยังไม่เพียงพอ setreg()เป็นขั้นตอนมากกว่าฟังก์ชั่น (สำหรับคนที่รู้จัก Pascal, Ada ... ) ซึ่งหมายความว่าจะไม่ส่งคืนสิ่งใด จริงๆแล้วมันคืนบางสิ่งบางอย่าง การออกที่ระบุ (เช่นการออกที่ไม่ใช่ข้อยกเว้น ) จะส่งคืนบางสิ่งเสมอ ตามค่าเริ่มต้นเมื่อเราลืมส่งคืนบางสิ่งจะถูกส่งคืน 0 ซึ่งจะใช้กับฟังก์ชันในตัว \=@a+setreg(...)นั่นเป็นเหตุผลในการแก้ปัญหาของเขาแสดงออกทดแทนที่เป็นจริง หากินใช่มั้ย

  • map()ยังสามารถใช้ ถ้าเราเริ่มต้นจากรายการที่มีเพียงครั้งเดียว (0 :let single_length=[0]) map(single_length, 'v:val + 1')เราอาจจะเพิ่มขึ้นก็ต้องขอบคุณ จากนั้นเราต้องคืนค่าความยาวใหม่ ซึ่งแตกต่างsetreg(), map()ผลตอบแทนการป้อนข้อมูลกลายพันธุ์ของมัน นั่นคือความสมบูรณ์แบบความยาวจะถูกเก็บไว้ที่ตำแหน่งแรก (และไม่ซ้ำใครและจะคงอยู่เช่นกัน) ในรายการ \=map(...)[0]การแสดงออกอาจจะมีการเปลี่ยน

  • add()เป็นหนึ่งที่ผมมักจะใช้ออกมาจากนิสัย (ฉันได้เพียงแค่คิดเกี่ยวกับmap()ความเป็นจริงและฉันไม่ได้ benched การแสดงของตนยัง) แนวคิดด้วยadd()คือการใช้รายการเป็นสถานะปัจจุบันและเพื่อผนวกสิ่งที่อยู่ท้ายสุดก่อนการทดแทนแต่ละครั้ง ฉันมักจะเก็บค่าใหม่ที่ส่วนท้ายของรายการและใช้เพื่อทดแทน ขณะที่ยังส่งกลับรายการการป้อนข้อมูลของมันกลายพันธุ์เราสามารถใช้:add() \=add(state, Func(state[-1], submatch(0)))[-1]ในกรณีของ OP เราจะต้องจำได้ว่ามีการตรวจพบการแข่งขันกี่ครั้งแล้ว การคืนความยาวของรายการสถานะนี้ก็เพียงพอแล้ว \=len(add(state, whatever))ดังนั้นฉัน


ฉันคิดว่าฉันเข้าใจอันนี้ แต่ทำไมเล่ห์เหลี่ยมกับอาเรย์และมันมีความยาวเมื่อเทียบกับการเพิ่มเข้าไปในตัวแปร?
hippietrail

1
นี่เป็นเพราะ\=ต้องการนิพจน์และเนื่องจากต่างจาก C i+=1ไม่ใช่สิ่งที่เพิ่มขึ้นและส่งคืนนิพจน์ ซึ่งหมายความว่าข้างหลัง\=ฉันต้องการบางสิ่งที่สามารถแก้ไขตัวนับและส่งคืนนิพจน์ (เท่ากับตัวนับนั้น) จนถึงตอนนี้สิ่งเดียวที่ฉันพบคือฟังก์ชั่นการจัดการรายการ (และพจนานุกรม) @Doktor OSwaldo ได้ใช้ฟังก์ชันกลายพันธุ์อื่น ( setreg()) ความแตกต่างคือsetreg()ไม่เคยส่งคืนสิ่งใดซึ่งหมายความว่าจะส่งกลับหมายเลข0เสมอ
Luc Hermitte

ว้าวน่าสนใจ! ทั้งกลอุบายของคุณและเขาวิเศษมากที่ฉันคิดว่าคำตอบของคุณจะได้รับประโยชน์จากการอธิบายคำตอบของคุณ ฉันจะสันนิษฐานว่ามีเพียงผู้ประกาศข่าวที่คล่องแคล่วที่สุดเท่านั้นที่จะรู้ว่าสำนวนที่ใช้งานไม่ได้เช่นนั้น
hippietrail

2
@hippietrail เพิ่มคำอธิบายแจ้งให้เราทราบหากคุณต้องการพื้นที่เฉพาะเพิ่มเติม
Luc Hermitte

13
 :let @a=1 | %s/search/\='replace'.(@a+setreg('a',@a+1))/g

aแต่ระวังมันจะเขียนทับลงทะเบียนของคุณ ฉันคิดว่ามันตรงไปตรงมาเล็กน้อยกว่าคำตอบของ luc แต่บางทีเขาอาจจะเร็วกว่า หากวิธีการนี้แย่กว่าเขาฉันจะชอบฟังความคิดเห็นใด ๆ ว่าทำไมคำตอบของเขาถึงดีกว่า ข้อเสนอแนะเพื่อปรับปรุงคำตอบใด ๆ จะได้รับการชื่นชมอย่างมาก!

(มันขึ้นอยู่กับคำตอบ SO ของ/programming/43539251/how-to-replace-finding-words-with-the-different-in-each-occurrence-in-vi-vim -edi / 43539546 # 43539546 )


ผมไม่เห็นว่าจะสั้นกว่า@a+setreg('a',@a+1) len(add(t,1))มิฉะนั้นนี่เป็นเคล็ดลับสกปรกอื่น ๆ :) ฉันไม่ได้คิดแบบนี้ เกี่ยวกับการใช้ฟังก์ชั่น mutating พจนานุกรมในข้อความทดแทนของ:sและsubstitute()ผมได้ตั้งข้อสังเกตนี้จะได้เร็วขึ้นมากว่าลูปอย่างชัดเจน - ด้วยเหตุนี้การดำเนินงานของฟังก์ชั่นในรายการของฉันใน LH-เป็นกลุ่ม-lib ฉันเดาว่าคำตอบของคุณจะเป็นของฉันอาจจะเร็วกว่าเล็กน้อยฉันไม่รู้
Luc Hermitte

2
เกี่ยวกับการตั้งค่าฉันชอบทางออกของฉันด้วยเหตุผลเดียว: มัน@aไม่ได้แก้ไข ในสคริปต์นี่เป็น IMO ที่สำคัญ ในขณะที่อยู่ในโหมดอินเทอร์แอคทีฟในฐานะผู้ใช้ปลายทางฉันจะรู้ว่าฉันสามารถลงทะเบียนใดได้บ้าง การล้อเล่นกับการลงทะเบียนนั้นมีความสำคัญน้อยกว่า ในโซลูชันของฉันในโหมดโต้ตอบตัวแปรทั่วโลกจะยุ่งเหยิง ในสคริปต์มันจะเป็นตัวแปรท้องถิ่น
Luc Hermitte

@LucHermitte ขออภัยทางออกของฉันไม่สั้นกว่าของคุณฉันควรอ่านให้ดีขึ้นก่อนที่จะเขียนคำสั่งดังกล่าว ฉันได้ลบข้อความดังกล่าวออกจากคำตอบของฉันแล้วและขออภัยในความผิดพลาด! ขอบคุณสำหรับข้อเสนอแนะที่น่าสนใจของคุณฉันขอขอบคุณ
Doktor OSwaldo

ไม่ต้องกังวลกับมัน เนื่องจาก regex มันง่ายที่จะคิดว่ามีหลายประเภท นอกจากนี้ฉันยอมรับโดยสมัครใจว่าโซลูชันของฉันมีความซับซ้อน คุณยินดีรับข้อเสนอแนะ :)
Luc Hermitte

1
แน่นอนคุณเข้มงวด เวลาส่วนใหญ่ฉันดึงข้อมูลอื่นที่ฉันเก็บไว้ในตำแหน่งสุดท้ายของอาเรย์ซึ่งเป็นสิ่งที่ (องค์ประกอบสุดท้าย) ฉันแทรกในตอนท้าย ยกตัวอย่างเช่นสำหรับผมสามารถเขียนสิ่งที่ต้องการ+3 \=add(thelist, 3 + get(thelist, -1, 0))[-1]
Luc Hermitte

5

ฉันพบคำถามที่คล้ายกัน แต่แตกต่างกันฉันถามสองสามปีที่ผ่านมาและจัดการเพื่อเปลี่ยนคำตอบอย่างใดอย่างหนึ่งโดยไม่เข้าใจสิ่งที่ฉันทำและมันทำงานได้ดี:

:let i = 1 | g/#\d\+\(\.\d\+\)\=/s//\=printf("#%d", i)/ | let i = i+1

โดยเฉพาะฉันไม่เข้าใจว่าทำไมของฉันไม่ใช้%หรือทำไมฉันใช้ตัวแปรธรรมดาที่คำตอบอื่น ๆ หลีกเลี่ยงด้วยเหตุผลบางอย่าง


1
นั่นคือความเป็นไปได้ ฉันคิดว่าข้อเสียเปรียบหลักของที่นี่คือคุณใช้คำสั่งทดแทนหนึ่งคำต่อการแข่งขัน ดังนั้นอาจช้ากว่านี้ สาเหตุที่เราไม่ใช้ตัวแปรธรรมดานั่นคือมันจะไม่ได้รับการปรับปรุงในs//gคำสั่งปกติ อย่างไรก็ตามมันเป็นทางออกที่น่าสนใจ บางที @LucHermitte สามารถบอกคุณได้มากกว่านี้เกี่ยวกับข้อดีข้อเสียเนื่องจากความรู้ของฉันเกี่ยวกับ vimscript ค่อนข้าง จำกัด เมื่อเทียบกับเขา
Doktor OSwaldo

1
@DoktorOSwaldo ฉันเดาว่าโซลูชันนี้ใช้งานได้นานขึ้น - โดยไม่คิดprintf()- เนื่องจากรายการถูกนำมาใช้ใน Vim 7 แต่ฉันต้องยอมรับว่าฉันจะไม่คาดหวัง (/ จำไม่ได้?) ที่<bar>อยู่ในขอบเขตของ:global- IOW สถานการณ์ที่ฉันคาดหวังคือใช้:subกับบรรทัดที่ตรงกันจากนั้นเพิ่มขึ้นiหนึ่งครั้งที่ส่วนท้ายสุด ฉันคาดว่าโซลูชันนี้จะช้าลงเล็กน้อย แต่มันสำคัญจริงๆหรือ สิ่งสำคัญคือความง่ายดายในการหาทางแก้ปัญหาจากหน่วยความจำ + การทดลอง & ข้อผิดพลาด ตัวอย่างเช่น Vimgolfers ชอบมาโคร
Luc Hermitte

1
@LucHermitte ใช่ฉัน ecpexted เดียวกันและไม่มีความเร็วไม่สำคัญ ฉันคิดว่ามันเป็นคำตอบที่ดีและฉันได้เรียนรู้บางสิ่งจากมันอีกครั้ง บางทีg/s//พฤติกรรมขอบเขตอนุญาตให้ใช้สำหรับเทคนิคสกปรกอื่น ๆ ขอบคุณทั้งคำตอบและการสนทนาที่น่าสนใจฉันไม่ได้เรียนรู้บ่อยครั้งมากจากการให้คำตอบ =)
Doktor OSwaldo

4

มีคำตอบที่ดีอยู่สามข้อ ในหน้านี้ แต่ตามที่Luc Hermitte แนะนำในการแสดงความคิดเห็นหากคุณกำลังทำสิ่งนี้สิ่งสำคัญคือความรวดเร็วและง่ายดายคุณสามารถลงวิธีแก้ปัญหาการทำงานได้

เช่นนี้เป็นปัญหาที่ฉันไม่ได้ใช้:substituteเลย: เป็นปัญหาที่สามารถแก้ไขได้อย่างง่ายดายโดยใช้คำสั่งโหมดปกติปกติและมาโครแบบเรียกซ้ำ:

  1. (ถ้าจำเป็น)'wrapscan'ครั้งแรกปิด นิพจน์ทั่วไปที่เราจะใช้จะตรงกับข้อความผลลัพธ์ที่ต้องการเช่นเดียวกับข้อความเริ่มต้นดังนั้นหาก'wrapscan'เปิดแมโครจะเล่นต่อไปเรื่อย ๆ (หรือจนกว่าคุณจะรู้ว่าเกิดอะไรขึ้นและกด<C-C>):

    :set nowrapscan
    
  2. ตั้งค่าคำค้นหาของคุณ (ใช้นิพจน์ทั่วไปพื้นฐานเดียวกันที่ได้กล่าวถึงแล้วในคำตอบที่มีอยู่):

    /#\d\+\(\.\d\+\)\?<CR>
    
  3. (ถ้าจำเป็น)กระโดดกลับไปที่นัดแรกโดยกดNหลายครั้งตามที่ต้องการ

  4. (ถ้าจำเป็น)เปลี่ยนการจับคู่แรกเป็นข้อความที่ต้องการ:

    cE#1<Esc> 
    
  5. ลบการ"qลงทะเบียนและเริ่มบันทึกแมโคร:

    qqqqq
    
  6. ดึงตัวนับปัจจุบัน:

    yiW
    
  7. ข้ามไปที่นัดต่อไป:

    n
    
  8. แทนที่ตัวนับปัจจุบันด้วยอันที่เราเพิ่งดึง:

    vEp
    
  9. เพิ่มตัวนับ:

    <C-A>
    
  10. qเล่นแมโคร การลงทะเบียน"qยังคงว่างเปล่าเพราะเราล้างข้อมูลในขั้นตอนที่ 5 ดังนั้นจึงไม่มีอะไรเกิดขึ้นในตอนนี้:

    @q
    
  11. หยุดการบันทึกแมโคร:

    q
    
  12. เล่นมาโครใหม่แล้วดู!

    @q
    

เช่นเดียวกับมาโครทั้งหมดนี่เป็นขั้นตอนหลายขั้นตอนเมื่ออธิบายตามที่ฉันได้ทำข้างต้น แต่โปรดทราบว่าจริง ๆ แล้วการพิมพ์สิ่งเหล่านี้ในนั้นรวดเร็วมากสำหรับฉัน: นอกเหนือจากการบันทึกแบบมาโคร - แบบบันทึกซ้ำ คำสั่งแก้ไขฉันกำลังทำงานตลอดเวลาในระหว่างการแก้ไข ขั้นตอนเดียวที่ฉันต้องทำทุกอย่างแม้ใกล้ถึงความคิดคือขั้นตอนที่ 2 ที่ฉันเขียนนิพจน์ทั่วไปเพื่อทำการค้นหา

จัดรูปแบบเป็นสองคำสั่งโหมดบรรทัดคำสั่งและชุดของการกดแป้นพิมพ์ความเร็วของการแก้ปัญหาประเภทนี้จะชัดเจนมากขึ้น: ฉันสามารถคิดต่อไปนี้สวยเร็วเท่าที่ฉันสามารถพิมพ์1 :

:set nowrapscan
/#\d\+\(\.\d\+\)\?
cE#1<Esc>qqqqqyiWnvEp<C-A>@qq@q

ฉันอาจคิดวิธีแก้ปัญหาอื่น ๆ ในหน้านี้ด้วยความคิดและการอ้างอิงของเอกสาร2แต่เมื่อคุณเข้าใจว่ามาโครทำงานได้อย่างไรพวกเขาจะสามารถแก้ไขได้อย่างรวดเร็วด้วยความเร็วเท่าที่คุณแก้ไข

1: มีหลายสถานการณ์ที่แมโครต้องการความคิดมากกว่า แต่ฉันคิดว่ามันไม่ได้เกิดขึ้นมากนักในทางปฏิบัติ และโดยทั่วไปแล้วสถานการณ์ที่เกิดขึ้นเป็นสถานการณ์ที่แมโครเป็นทางออกในทางปฏิบัติเท่านั้น

2: ไม่ได้หมายความว่าผู้ตอบคำถามคนอื่นไม่สามารถหาวิธีแก้ปัญหาของพวกเขาในทำนองเดียวกันได้อย่างง่ายดาย: พวกเขาต้องการทักษะ / ความรู้ที่ฉันไม่สามารถทำได้ง่ายๆเพียงปลายนิ้วสัมผัส แต่ผู้ใช้ Vim ทุกคนรู้วิธีใช้คำสั่งแก้ไขปกติ!

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