ฉันจะฟอร์แมตสตริงแบบหลายบรรทัดเป็นกลุ่มเมื่อใช้ไฟล์ Python ได้อย่างไร


23

สมมติว่าฉันกำลังแก้ไขโค้ด Python ในกลุ่มที่มีลักษณะดังนี้:

myobj.myfunc("Some string parameter that goes on and on and on and on and sometimes doesn't"
             "split very"
             "neatly over different lines so that"
             "it is formatted attractively")

ฉันต้องการฟอร์แมตใหม่เพื่อให้รีโฟลว์สูงถึงระดับที่textwidthฉันตั้งไว้:

myobj.myfunc("Some string parameter that goes on and on and "
             "on and on and sometimes doesn't split very "
             "neatly over different lines so that it is "
             "formatted attractively")

มีวิธีง่ายๆในการทำเช่นนี้หรือไม่? หากนี่คือย่อหน้าข้อความทั่วไปgqipหรือที่คล้ายกันจะมีประโยชน์ แต่จะไม่จัดการกับคำพูดที่ใช้ในการลบสตริง

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


1
คำถามที่คล้ายกันที่นี่: vim.1045645.n5.nabble.com/ ...
Andrew Ferrier

3
คุณคิดว่าการเขียนรหัสใหม่เป็น"""multi-line string"""?
200_success

1
@ 200_ ความสำเร็จนั่นเป็นเคล็ดลับที่ยอดเยี่ยมขอบคุณ ฉันไม่รู้เกี่ยวกับคุณสมบัติของ Python เลย ดูเหมือนว่าจะใช้งานได้เป็นส่วนใหญ่ - แม้ว่าพารามิเตอร์ทั้งหมดของฟังก์ชั่นจะได้รับการปรับปรุงใหม่ซึ่งไม่เหมาะ ฉันคิดว่าคำถามของฉันยังคงใช้ได้สำหรับประเภทของสตริงที่ฉันมีและแน่นอนสำหรับภาษาอื่น ๆ
Andrew Ferrier

2
โปรดทราบว่าสตริงหลายบรรทัดจะเพิ่มอักขระช่องว่างซึ่งอาจเป็นปัญหาหากช่องว่างมีความสำคัญในสตริง
Matt Boehm

คำถามที่เกี่ยวข้องมาก: vi.stackexchange.com/questions/2135/ … ...
Martin Tournoij

คำตอบ:


6

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

function ReformatMultiLines()
  let brx = '^\s*"'
  let erx = '"\s*$'
  let fullrx = brx . '\(.\+\)' . erx
  let startLine = line(".")
  let endLine   = line(".")
  while getline(startLine) =~ fullrx
    let startLine -= 1
  endwhile
  if getline(endLine) =~ erx
    let endLine += 1
  endif
  while getline(endLine) =~ fullrx
    let endLine += 1
  endwhile
  if startLine != endLine
    exec endLine . ' s/' . brx . '//'
    exec startLine . ' s/' . erx . '//'
    exec startLine . ',' . endLine . ' s/' . fullrx . '/\1/'
    exec startLine . ',' . endLine . ' join'
  endif
  exec startLine
  let orig_tw = &tw
  if &tw == 0
    let &tw = &columns
    if &tw > 79
      let &tw = 79
    endif
  endif
  let &tw -= 3 " Adjust for missing quotes and space characters
  exec "normal A%-%\<Esc>gqq"
  let &tw = orig_tw
  let endLine = search("%-%$")
  exec endLine . ' s/%-%$//'
  if startLine == endLine
    return
  endif
  exec endLine
  exec 'normal I"'
  exec startLine
  exec 'normal A "'
  if endLine - startLine == 1
    return
  endif
  let startLine += 1
  while startLine != endLine
    exec startLine
    exec 'normal I"'
    exec 'normal A "'
    let startLine += 1
  endwhile
endfunction

จากนั้นคุณสามารถใช้กับ:call ReformatMultiLines()และ / หรือใช้ในการแมป


6

หากนี่เป็นเหตุการณ์ปกติคุณควรมองหาปลั๊กอินหรือใช้ฟังก์ชั่นของ @Sukima ถ้าฉันกำลังทำสิ่งนี้ในทันทีนี่คือสิ่งที่ฉันอาจทำ:

  1. เพิ่มขึ้นบรรทัดใหม่หลังจากการเปิด paren และก่อนการปิด paren เพื่อให้สตริงอยู่ในบรรทัดแยกกัน

    myobj.myfunc(
                 "Some string parameter that goes on and on and on and on and sometimes doesn't"
                 "split very"
                 "neatly over different lines so that"
                 "it is formatted attractively"
    )
    
  2. เลือกบรรทัดที่มีสตริงและลบเครื่องหมายคำพูดล้อมรอบ: :norm ^x$x

  3. ลดความกว้างของข้อความ (ไปยังบัญชีสำหรับคำพูดที่หายไป) :set tw-=2
  4. เลือกซ้ำและจัดรูปแบบ: gvgq
  5. แก้ไขความกว้างของข้อความ: :set tw+=2
  6. gv:norm I"<Esc>A"คำพูดเพิ่มอีกครั้ง: แทนการที่<Esc>คุณต้องการแทรก escape ตามตัวอักษรโดยพิมพ์ ctrl-v ตามด้วยคีย์ escape เนื่องจากฉันจับคู่ jj เพื่อหลบหนีฉันมักจะพิมพ์ jj ที่นี่
  7. เลือกใช้ J เพื่อเข้าร่วมสองบรรทัดแรก / สองครั้งสุดท้าย เมื่อฉันมีสตริงที่ยาวมากในไพ ธ อนเช่นนี้ฉันมักจะชอบที่จะเริ่มมันในบรรทัดถัดไปและเยื้องมันเพียงหนึ่งระดับมากกว่าบรรทัดก่อนหน้า มันให้พื้นที่แนวนอนมากขึ้นสำหรับสายและรู้สึกเป็นธรรมชาติมากขึ้นสำหรับฉัน หรือคุณสามารถบันทึกสตริงเป็นตัวแปรที่ด้านบน สมมติว่าเป็นสตริงแบบคงที่คุณสามารถบันทึกลงในตัวแปรส่วนกลางเพื่อให้อยู่ในระดับการเยื้องที่ต่ำกว่ามากและสามารถใส่ลงในบรรทัดที่น้อยลงได้ โปรดทราบว่าคุณจะต้องเข้าร่วม paren การปิดในบรรทัดเดียวกันคุณอาจต้องการลด / เพิ่มความกว้างของข้อความโดย 3 แทน 2

1
ขอบคุณ ฉันแค่พยายามนี้ แต่ผลในการ:set tw-=2 E487: Argument must be positive: tw-=2ไวยากรณ์ไม่ถูกต้องหรือไม่
Andrew Ferrier

1
ตรวจสอบมูลค่าปัจจุบันของ textwidth :set tw?กับ ฉันเดาว่าคุณได้ตั้งค่าความกว้างของข้อความเป็น 0 ขั้นตอนเหล่านี้ถือว่าความกว้างของข้อความเริ่มต้นขึ้นตามจำนวนตัวอักษรที่คุณต้องการต่อบรรทัด
Matt Boehm

ในตัวอย่างของคุณคุณอาจต้องการs/2/3/และเพิ่มช่องว่างก่อนเครื่องหมายคำพูดปิดสตริงที่ยาวของคุณจะไม่มีระยะห่างระหว่างคำที่เหมาะสม
cdosborn

1

รหัสการแยกวิเคราะห์และการจัดรูปแบบเป็นเรื่องยากโดยเฉพาะอย่างยิ่งสำหรับภาษาแบบไดนามิกเช่น Python

แทนการพยายามที่จะแยกหลามใน Vimscript ผมขอแนะนำให้คุณสามารถใช้การจัดรูปแบบภายนอกเช่นyapf ด้วยคำตอบของฉันที่นี่คุณสามารถเขียนสิ่งนี้โดยอัตโนมัติเมื่อเขียนด้วย:

augroup write_cmd
    autocmd BufWritePre *.py call s:write_cmd('yapf')
augroup end

s:write_cmd()ฟังก์ชั่นที่อยู่ในคำตอบอื่น ๆ - ฉันจะไม่เพิ่มได้ที่นี่ดังนั้นฉันจะไม่ได้มีการปรับปรุงดังกล่าวในสถานที่สองถ้าฉันพบข้อผิดพลาด :-)

นอกจากนี้คุณยังสามารถตั้งค่าformatprgให้กับตนเองและรูปแบบด้วยyapfgq


สวัสดี คำตอบที่เป็นประโยชน์ แต่ฉันกำลัง downvoting เนื่องจากฉันไม่คิดว่ามันจะตอบคำถามนี้: คำถามนี้เป็นคำถามที่ถามเกี่ยวกับการจัดรูปแบบสตริงหลายบรรทัดโดยเฉพาะซึ่งyapfดูเหมือนจะไม่ทำ อย่างไรก็ตามฉันเห็นด้วยดูเหมือนว่าเป็นเครื่องมือที่มีประโยชน์
Andrew Ferrier

@AndrewFerrier ยุติธรรมเพียงพอ; ฉันสาบานได้ว่าฉันเห็นรูปแบบการจัดรูปแบบใหม่เมื่อฉันทดสอบวันนี้ แต่ไม่สามารถใช้งานได้ในตอนนี้: - / เดาว่าฉันสับสน
Martin Tournoij

0

ฟังก์ชั่นต่อไปนี้และการแมปที่เกี่ยวข้องช่วยแก้ปัญหานี้ให้ฉันได้:

function! BreakMultlineString(quote)
let c = 100
while c == 100
    normal 100|
    let c = virtcol('.')
    if c == 100
        execute "normal ," . a:quote
    endif
endwhile
endfunction

function! JoinMultilineString()
    let c = "'"
    while c == "'" || c == '"'
        normal gj^
        let c = matchstr(getline('.'), '\%' . col('.') . 'c.')
        normal k
        if c == "'" || c == '"'
            normal ,j
        endif
    endwhile
endfunction

" break lines
nnoremap <Leader>" 100\|Bi"<CR>"<Esc>
nnoremap <Leader><Leader>" :call BreakMultlineString('"')<CR>
nnoremap <Leader>' 100\|Bi'<CR>'<Esc>
nnoremap <Leader><Leader>' :call BreakMultlineString("'")<CR>

" join lines
nmap <Leader>j Jds'ds"x
nnoremap <Leader>J :call JoinMultilineString()<CR>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.