Seçimdeki veya eşleşmedeki her satıra artan bir sayı ekleme


10

Çözmem için iki genel yaklaşım düşünebileceğim bir sorunum var, ama her iki yaklaşım için de detaylar bilmiyorum.

...
Level 1:    cũng    also
Level 1:    và      and
Level 1:    như     like; such as
Level 2:    các     plural marker
Level 2:    của     belonging to
...

"Level n" ile başlayan her satır için "01" ile başlayan bir sayı eklemek istiyorum. Basitlik için numarayı başlayalım.

Yaklaşım 1: Aynı Seviyeye sahip tüm satırları manuel olarak seçin. Yakında öğrenmek için sihir çağırın.

Yaklaşım 2: Bir arama yazın ve her bir eşleşmede her bir eşleşmeyle birer birer artan bir eşleşme metninde bir sayı içeren belirli bir Düzeye sahip tüm satırlarla eşleşen bir arama yazın.

StackOverflow veya diğer Vim sitelerinde benzer sorular buldum , ancak her biri aşağıdaki sorunlardan bir veya daha fazlasına sahip gibi görünüyor:

  1. Rasgele ancak artan bir sayı yerine geçerli satır numarasını eklemekle ilgilidir.
  2. Sayıyı sıfırla doldurmaz.
  3. Aslında Windows 7'de çalışan Vim 7.4'ümdeki seçimler için çalışmıyor. (Bunlar hataya neden oluyor E481: No range allowed.)

Windows'ta gVim'i mswin.vim ile çalıştırıyorum, ancak kurulumu özelleştirmek zorunda kalmadan tüm vanilya Vim yüklemelerinde çalışan bir çözüm en iyi olabilir.


Soru için düşünebildiğim en iyi etiketler mevcut değil: seçim ve aralık bu yüzden bu etiketlerden birini yeniden etiketlemek veya oluşturmaktan çekinmeyin.
hippietrail

1
Bu eklenti sorununuz için tam bir çözüm değildir, ancak sayı sütunları eklemek için çok faydalıdır: VisIncr . Dokümanlar burada . FWIW.
lcd047

Yanıtlar:


17

Https://vi.stackexchange.com/a/818/227 adresindeki cevaba benzer şekilde global komutu kullanabilirsiniz.

Bununla birlikte, vim'e bir modelle eşleşen satırları aramasını ve ardından komutları gerçekleştirmesini söyleyebilirsiniz.

Sizin durumunuzda, "Seviye N:" ile başlayan satırlara metin eklemek istersiniz, böylece global komutumuz

:g/^Level \d:/{COMMANDS}

Komut için substitute komutunu (normal ifade değiştirme) kullanma

Komutlar daha eğlenceli. Değişkenleri kullanmak kolay olduğu için genellikle böyle şeyler için düzenli bir ifade değişikliği yapmak isterim.

Sorunuz için örnek

:let i = 1 | g/^Level \d:/s/^/\=printf("%02d ", i)/ | let i = i+1

Nasıl çalışır

İkame komutunun değiştirme bölümünde bir ifade olabilir.

Yapacağımız ilk şey i, başlangıç değişkeni olarak bir değişken ayarlamaktır . 1'i seçtim, ancak herhangi bir sayı yapacak.let i = 1

Ardından, eşleşen satırlarda bir eylemde bulunmamızı sağlayan global komutumuzu çalıştırıyoruz. g/^Level \d:/

Global komutumuzun değeri girmesini ve substitüsyon komutunu ve let komutunu kullanarak sayacımızı artırmasını sağlayacağız.s/^/\=printf("%02d ", i)/ | let i = i+1

Değiştirme komutunun normal ifadesi satırın başlangıcını bulur ve ^bir ifadeyle değiştirir ve ifademiz biçimlendirilmiş bir baskının sonucu olacaktır. C dilinde olduğu gibi, vim'in printf formatlama parametrelerini alır. %02d"" ifadesi, bir argümanı ondalık sayı gibi dönüştürmek d, en az 2 boşluk 2ve 0 ile doldurmak anlamına gelir 0. Ayrıntılar ve diğer dönüştürme seçenekleri (kayan nokta biçimlendirme dahil) için bkz :help printf. Printf'e sayım değişkenimizi veriyoruz ive bu bize 01ilk kez, 02ikinci kez vb.

Ben d: sonra bir boşluk koymak unutmayın "%02d ". Bunu soruda sormadınız (ve örnek çıktı görmedim), ancak sayıyı "Seviye" kelimesinden ayırmak istediğinizden şüphelendim. Girilen sayının Seviye L'nin hemen yanında olması için printf'ye verilen dizeden boşluğu kaldırın.

Son olarak, bu let i = i + 1her değişiklikten sonra sayacımızı arttırır.

Bu genellikle, diğer ölçütlerle eşleşen satır bölümlerini rastgele işlevsel verilerle değiştirmek için uygulanabilir.

Birleşik normal komutları kullanma

Bu, basit eklemeler veya karmaşık düzenleme için iyidir. Yerine koymada olduğu gibi, eşleşmek için global'i kullanacağız, ancak normal ifade yerine koymak yerine, kullanıcı tarafından yazılmış gibi bir dizi işlem gerçekleştireceğiz.

Sorunuz için örnek

:let i = 1 | g/^Level \d:/execute "normal! I" . printf("%02d ", i) | let i = i+1

Nasıl çalışır

Kullanılan değerler ikame değere çok benziyor (hala 2 rakamla dolgulu hale getirmek için sayımızı biçimlendirmek için printf kullanıyoruz), ancak işlem farklı.

Burada bir dizeyi alan ve dizeyi ex komutu ( :help :exe) olarak çalıştıran execute komutunu kullanıyoruz . Verilerimizle "normal! I" i ilk kez "normal! I01" ve ikinci kez "normal! I02" olacak şekilde birleştiren bir dize oluşturuyoruz.

normalKomut gerçekleştirdiği operasyonlar normal modda sanki. Bu örnekte, normal komutumuz Isatırın başına eklenir. Eğer ddkullansaydık çizgiyi siler o, eşleşen çizgiden sonra yeni bir çizgi açardı. Sanki Inormal modda yazdınız (veya başka bir işlem yapıyorsunuz ). Kullandığımız !SONRA normalemin hiçbir eşleştirmeleri yolumuza olsun yapmak. Bkz :help :normal.

O zaman eklenen ilk örnekte olduğu gibi printf değerimizdir.

Bu yöntem regex'ten daha meraklı olabilir, çünkü execute "normal! ^2wy" . i . "th$p"metnin başına gidecek ^, 2 kelime ileri gidecek 2w, '' h 'karakterine kadar çekilecek y" . i . "th, satırın sonuna $gidip yapıştıracak gibi şeyler yapabilirsiniz p.

Bu neredeyse bir makro çalıştırmak gibidir, ancak aslında bir kayıt kullanmaz ve herhangi bir ifadeden dizeleri birleştirebilir. Bunu çok güçlü buluyorum.

Her seviyenin kendi sayacı olduğu yaklaşım

Her seviyenin kendi sayacını almasını isteyebilirsiniz. Önceden maksimum seviye sayısını biliyorsanız, aşağıdakileri yapabilirsiniz (en büyük seviyeyi bulmak için ekstra kod eklemek çok zor olmayabilir, ancak bu cevabı çok uzun sürebilir.

İlk olarak, zaten bir tamsayı olarak kullanmış olursak, i serbest bırakalım. İ'yi bir listeye dönüştüremeyiz, onu bu şekilde yaratmalıyız.

:unlet! i

Daha sonra, i'yi seviye sayısını içeren bir liste olarak ayarlayalım. Sorunuzda 2 tane gösterdiniz, ancak eğlenmek için 10 olduğunu varsayalım. Liste indeksleme 0 tabanlı olduğundan ve listeniz gibi 1 için düzeltme yapmak istemiyorum, sadece yeterli elemanlar (11) oluşturacağız ve asla 0 indeksini kullanmayacağız.

:let j = 0
:let i = []
:while j < 11 | let i += [1] | let j += 1 | endwhile

Sonra, seviye numarasını almak için bir yola ihtiyacımız var. Neyse ki, ikame de bir işlev olarak mevcuttur, bu yüzden ona satırımızı vereceğiz ve seviye numarasını çıkaracağızsubstitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")

İ artık 11 1saniyelik bir liste olduğundan (her bir dizin seviyemiz için sayaçtır), şimdi bu değiştirmenin sonucunu kullanmak için yukarıdaki örneklerden birini ayarlayabiliriz:

Yedek komut ile:

:unlet! i | unlet! j | let j = 0 | let i = [] | while j < 11 | let i += [1] | let j += 1 | endwhile
:g/^Level \d:/let ind=str2nr(substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")) | s/^/\=printf("%02d ", i[ind])/ | let i[ind] += 1

Normal komut ile:

:unlet! i | unlet! j | let j = 0 | let i = [] | while j < 11 | let i += [1] | let j += 1 | endwhile
:g/^Level \d:/let ind=str2nr(substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")) | execute "normal! I" . printf("%02d ", i[ind]) | let i[ind] += 1

Örnek girdi:

Level 1: stuff

Level 1: Stuff

Some text
Level 3: Other

Level 1: Meh

Level 2: More

Örnek çıktı:

01 Level 1: stuff

02 Level 1: Stuff

Some text
01 Level 3: Other

03 Level 1: Meh

01 Level 2: More

Vay canına, çok ansiklopedik. Sadece ilk bölümü okudum ve Vim hakkında son birkaç yıl içinde yaşadığımdan daha fazlasını öğrendiğimi hissediyorum. Bu, Stack Exchange'i ortalama Soru-Cevap sitelerinden daha iyi yapan ve aynı zamanda Vim'e özgü bir SE'ye sahip olmanın faydalarını gösteren bir cevaptır.
hippietrail

3

Sen oluşturabileceğiniz https://stackoverflow.com/a/4224454/15934 sıfır pad Rakamlarınız için.

" A reminder: how to start numbers at the first line
:'<,'>s/^\s*\zs/\=(line('.') - line("'<")+1).'. '

Ancak, sayıların doldurulmasını kolaylaştırmak için bir çift işlev ve bir komut seçerdim:

command!  -range=% -nargs=? PrependNumbers <line1>,<line2>call s:Prepend(<args>)

function! s:ReplExpr(nb_digits, number)
  return repeat('0', a:nb_digits - strlen(a:number)).a:number
endfunction

function! s:Prepend(...) range
  let pattern = a:0 > 0 ? '\ze'. a:1 : '^'
  let nb_values = (a:lastline - a:firstline) + 1
  let nb_digits = strlen(nb_values)
  exe ':'.a:firstline.','a:lastline.'s#'.pattern.'#\=s:ReplExpr(nb_digits, 1+ line(".")-'.a:firstline.')." "#'
endfunction

Bundan sonra satırlarınızı seçin ve yazın :PrependNumber(göreceksiniz :'<,'>PrependNumber. [Not: Komut isteğe bağlı bir parametre alır: numaranın ekleneceği kalıp]


Ancak line(".")"geçerli satır numarasını kullan" anlamına gelmiyor mu? Bu benim sorunum 1. önceki cevapları ile bulabildiğim.
hippietrail

1
Evet öyle. Bu yüzden aralıktaki ilk satırın satır numarasını çıkarıyorum.
Luc Hermitte

Ah Tamam Henüz test etmedim çünkü Vim'de bir senaryoyu nasıl gireceğimi bile hatırlayamıyorum ... önce bunu okumalıyım (-:
hippietrail

1
Pencerelerin altında olduğunuzda, kodu kopyalayın $HOME/vimfiles/plugin/whatevernameyouwish.vim. Ya da $HOME/_vimrc(windows dosya adı) tercihinize göre (ilk kez). Makinenizde $ HOME'un ne olduğundan emin değilseniz, vim'e bunun ne olduğunu düşündüğünü sorun ->:echo $HOME
Luc Hermitte

1
:sourceVim betiğinin doğru dizine doğru şekilde yüklenmiş olması bile gerekmez (dosya türüne özgü eklentiler için {rtp} / plugin veya {rtp} / ftplugin / {filetype} / ftplugin). :sourceon yıldan fazla bir buçuk yıl önce oynamamız gereken şeydi.
Luc Hermitte

2

Bir makro kaydederek ona yaklaşabilirsiniz. Orijinal dosyanızla başlayarak, ilk örneği numarayla birlikte ekleyin.

01 Level 1:    cũng    also
Level 1:    và      and
Level 1:    như     like; such as
Level 2:    các     plural marker
Level 2:    của     belonging to

İmlecinizi üzerine getirin 01, seçin ve işaretleyin yiw. Şimdi eylemlerinizi bu noktadan itibaren kaydetmek istiyorsunuz.

qq/^Level 1<CR>P<C-A>A<space><esc>0yiwq

  • qq Q kaydında bir makro başlatma
  • /^Level 1<CR> "Seviye 1" ile başlayan bir satır arayın
  • P imleçten önce yapıştır (numaranı içerir)
  • <C-A> sayıyı arttırır
  • A<space><esc> Sayıdan sonra boşluk ekle
  • 0 Başlangıca git
  • yiw geçerli numarayı çek
  • q Makroyu bitir

Sonra kullanarak bu makroyu tekrarlayın @q.


1
<C-A>a + kontrolü? Bu, Windows'daki Vim'deki her şeyi seçer.
hippietrail

Control + a'dır. Vim'de bir sayıyı arttırmalıdır. Anahtar bağlarınızı Vim eylemleri yerine Windows eylemleri yapacak şekilde değiştirdiyseniz, insanların burada paylaştığı şeylerin çoğunu yapamayacaksınız.
jecxjo

Windows için Vim sürümü, birinin sonsuz bilgeliğinden dolayı farklı bağlarla gelmez. Sadece vanilyayı kutudan çıkardığım ciltler kullanıyorum. Yirmi yılı aşkın bir süredir Vim anahtar bağlayıcısını hiç değiştirmedim, hatırlayabiliyorum (-:
hippietrail

Durum böyle olmamalı, Windows kurulumumda normal vim bağlamaları var. Başkasının vim yapısını kurmanız mümkün olabilir mi? Veya "Kolay" modunda vim çalıştırıyor olabilir misiniz? Windows normal ve kolay mod seçenekleriyle masaüstü simgeleri yükler inanıyorum.
jecxjo

3
Hayır, çünkü Windows'daki varsayılan yükleme mswin.vim dosyasını yükler. Kendi vimrc'inizi yaparsanız ve mswin.vim'i yüklemezseniz, normal vim bağlarını alırsınız. Tüm yüklemelerim (Linux, Mac ve Windows) için tek bir vimrc tutuyorum ve asla mswin.vim ile ilgilenmiyorum. Bu konu hakkında daha fazla bilgi için bkz. Stackoverflow.com/questions/289681/…
jecxjo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.