Her maçı artan sayaç ile nasıl değiştirebilirim?


14

Belirli bir paternin her tekrarını aramak ve 1her maç için bir ondalık sayı ile başlayan ve ondalık bir sayı ile değiştirmek istiyorum .

Bir sayacı artırmak değil, her maçı sabit bir miktarda değiştirmekle ilgili olduğu gibi benzer şekilde ifade edilmiş sorular bulabilirim. Diğer benzer sorular, artan bir sayaçtan ziyade satır numaraları eklemekle ilgilidir.

Örnek, önce:

#1
#1.25
#1.5
#2

Sonra:

#1
#2
#3
#4

Gerçek verilerimin, yeniden numaralandırmak istediğim şeyler çevresinde çok daha fazla metni var.


2
eğer varsa perldo, kullanabilirsiniz:%perldo s/#\K\d+(\.\d+)?/++$i/ge
Sundeep

@Sundeep: Windows 10'da vanilyalı olduğumu söylemeliydim, üzgünüm!
hippietrail

Yanıtlar:


15

Bir devletle yer değiştirmeye ihtiyacınız var. SO bu tür sorunlar için (/ birkaç?) Tam bir çözüm sağladığını hatırlıyorum .

İşte ilerlemenin başka bir yolu (1). Şimdi 2 adıma geçeceğim:

  • kullanacağım kirli ve kıvrımlı numara için ihtiyacım olan bir kukla liste değişkeni
  • her bir eşleme olayı dolduruyorum ben bu kukla dizinin len eklemek bir ikame.

Hangi verir:

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

Normal ifadeleri vimlemeye alışkın değilseniz, hangi alt kalıbı eşleştirdiğimi belirtmek için kullanıyorum :h /\zsve \zesonra bir nokta ve diğer rakamlarla izlenen bir dizi rakamla eşleşiyorum. Bu herhangi bir kayan nokta sayısı için mükemmel değildir, ancak burada yeterlidir.

Not: Basit bir arayüz için bir çift işlev + komutuna sarmanız gerekir. Yine, SO / vim üzerinde örnekler var ( burada , burada , burada ) Bugünlerde bu hileyi bir komuta sarmayı umursamayacak kadar vim biliyorum. Gerçekten de ilk denemede bu komutu yazabiliyorum, komutun adını hatırlamak birkaç dakika sürecek.


(1) Amaç, ikameler arasındaki bir durumu koruyabilmeyi ve mevcut olayı mevcut duruma bağlı bir şeyle değiştirebilmektir.

Bu sayede :s\=bir hesaplamadan kaynaklanan bir şey ekleyebiliyoruz.

Devlet sorununu ortadan kaldırır. Harici bir durumu yöneten bir fonksiyon tanımlarız veya kendimizi harici bir durumu güncelleriz. C dilinde (ve ilgili dillerde), length++veya gibi bir şey kullanabilirdik length+=1. Ne yazık ki, vim komut dosyalarında, +=kutunun dışında kullanılamaz. İle :setveya ile birlikte kullanılması gerekir :let. Bu, :let length+=1bir sayıyı artırır ancak hiçbir şey döndürmez. Yazamayız :s/pattern/\=(length+=1). Başka bir şeye ihtiyacımız var.

Değişen işlevlere ihtiyacımız var. yani girdilerini değiştiren işlevler. Biz setreg(), map(), add()muhtemelen daha. Onlarla başlayalım.

  • setreg()bir kaydı değiştirir. Mükemmel. setreg('a',@a+1)@Doktor OSwaldo'nun çözümünde olduğu gibi yazabiliriz . Ve yine de, bu yeterli değil. setreg()bir fonksiyondan çok bir prosedürdür (Pascal, Ada'yı bilenler için). Bu, hiçbir şey döndürmediği anlamına gelir. Aslında, bir şey döndürüyor. Nominal çıkış ( istisna dışı çıkışlar) her zaman bir şeyler döndürür. Varsayılan olarak, bir şeyi iade etmeyi unuttuğumuzda, 0 döndürülür - yerleşik işlevlerle de uygulanır. Bu yüzden çözümünde yerine koyma ifadesi aslında \=@a+setreg(...). Zor, değil mi?

  • map()de kullanılabilir. Bir listeden tek bir 0 ( :let single_length=[0]) ile başlasak, sayesinde artırabiliriz map(single_length, 'v:val + 1'). O zaman yeni uzunluğu iade etmeliyiz. Bunun aksine setreg(), map()mutasyona uğramış girdisini döndürür. Bu mükemmel, uzunluk listenin ilk (ve benzersiz ve dolayısıyla da son) konumunda saklanır. Değiştirme ifadesi olabilir \=map(...)[0].

  • add()alışkanlıktan sık sık kullandığım şey ( map()aslında hakkında konuştum ve henüz kendi performanslarını test etmedim). Buradaki fikir, add()bir listeyi geçerli durum olarak kullanmak ve her bir değişiklikten önce sonuna bir şey eklemektir. Yeni değeri genellikle listenin sonunda saklarım ve değiştirme için kullanırım. Gibi add()aynı zamanda mutasyona uğramış giriş listesini döndürür, biz kullanabilirsiniz: \=add(state, Func(state[-1], submatch(0)))[-1]. OP durumunda, şu ana kadar kaç eşleşme tespit edildiğini hatırlamamız gerekiyor. Bu durum listesinin uzunluğunu döndürmek yeterlidir. Dolayısıyla benim \=len(add(state, whatever)).


Bunu anlıyorum, ama neden dizi ile hile ve uzunluğu bir değişkene bir ekleme ile karşılaştırıldığında?
hippietrail

1
Bunun nedeni \=, bir ifade beklemesidir ve C'den farklı olarak, i+=1artan ve bir ifade döndüren bir şey değildir . Bu, arkasında \=bir sayacı değiştirebilecek bir şeye ihtiyacım olduğu ve bu ifadeyi (bu sayaca eşit) döndüren anlamına gelir . Şimdiye kadar bulduğum tek şey liste (ve sözlük) manipülasyon fonksiyonları. @ Doktora OSwaldo başka bir mutasyon işlevi ( setreg()) kullandı. fark, setreg()hiçbir zaman bir şey döndürmemesi, yani her zaman sayıyı döndürmesidir 0.
Luc Hermitte

Vay ilginç! Hem hileniz hem de onun o kadar büyülü ki, cevaplarınızın cevaplarınızda onları açıklamaktan fayda sağlayacağını düşünüyorum. Sadece en akıcı vimscript'lerin böylesi sezgisel olmayan deyimleri bildiğini varsayıyorum.
hippietrail

2
@hippietrail. Açıklamalar eklendi. Daha spesifik hassasiyetlere ihtiyacınız olup olmadığını bana bildirin.
Luc Hermitte

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

Ancak dikkat edin, kaydınızın üzerine yazacaktır a. Sanırım luc'ın cevabından biraz daha düz, ama belki daha hızlı. Bu çözüm bir şekilde ondan daha kötü ise, cevabının neden daha iyi olduğu hakkında herhangi bir geri bildirim duymak isterim. Cevabı geliştirmek için herhangi bir geri bildirim çok takdir edilecektir!

(Ayrıca benim SO cevabına dayanmaktadır /programming/43539251/how-to-replace-finding-words-with-the-different-in-each-occurrence-in-vi-vim -edi / 43539546 # 43539546 )


Nasıl @a+setreg('a',@a+1)daha kısa olduğunu göremiyorum len(add(t,1)). Aksi takdirde, bu güzel bir diğer kirli hile :). Ben de öyle değil. Değiştirme metninde bir sözlük mutasyon işlevinin kullanımı ile ilgili olarak, :sve substitute()bunun açık döngülerden çok daha hızlı olduğunu belirttim - dolayısıyla lh-vim-lib'deki liste işlevlerimin uygulanması . Sanırım çözümün benimkiyle aynı olacak, biraz daha hızlı olabilir, bilmiyorum.
Luc Hermitte

2
Tercihler ile ilgili olarak, çözümümü tek bir nedenden dolayı tercih ederim: @adeğiştirilmemiş bırakır . Komut dosyalarında bu önemli IMO'dur. Etkileşimli moddayken, son kullanıcı olarak hangi kaydı kullanabileceğimi bileceğim. Bir kayıtla uğraşmak daha az önemlidir. Benim çözümümde, etkileşimli modda, global bir değişkenle karıştırılıyor; bir komut dosyasında yerel bir değişken olur.
Luc Hermitte

@LucHermitte Üzgünüm, benim çözümüm sizinkinden daha kısa değil, böyle bir ifade yazmadan önce daha iyi okumalıyım. Söz konusu ifadeyi cevabımdan kaldırdım ve özür dilemek istiyorum! İlginç geri bildiriminiz için teşekkür ederim, çok teşekkür ederim.
Doktor OSwaldo

Endişelenme. Normal ifade nedeniyle, yazacak çok şey olduğunu düşünmek kolaydır. Ayrıca, gönüllü olarak kabul ediyorum ki çözümüm kıvrımlı. Geri bildirim için bekliyoruz. :)
Luc Hermitte

1
Gerçekten sertsiniz. Çoğu zaman, dizinin son konumunda sakladığım başka bir bilgiyi ayıklarım. Mesela, a +3gibi bir şey yazabilirim \=add(thelist, 3 + get(thelist, -1, 0))[-1].
Luc Hermitte

5

Birkaç yıl önce sorduğum benzer ama farklı bir soru buldum ve ne yaptığımı tam olarak anlamadan cevaplarından birini değiştirmeyi başardım ve harika çalışıyor:

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

Özellikle benimkinin neden kullanmadığını %veya diğer cevapların nedense kaçındığı düz bir değişken kullandığımı anlamıyorum.


1
bu da bir olasılıktır. Sanırım buradaki ana dezavantaj, maç başına bir yedek komut kullanmanızdır. Yani muhtemelen daha yavaş. Düz değişken kullanmamamızın nedeni, normal s//gifadede güncellenmeyeceğidir . Her neyse, ilginç bir çözüm. Belki @LucHermitte size artıları ve eksileri hakkında daha fazla bilgi verebilir, çünkü vimscript hakkındaki bilgim onunla karşılaştırıldığında oldukça sınırlıdır.
Doktor OSwaldo

1
@DoktorOSwaldo. Sanırım bu çözüm daha uzun bir süredir çalışıyor - printf()olsa da - Listeler Vim 7'de tanıtıldı. Ama itiraf etmeliyim ki <bar>, kapsamına ait olmasını beklemeyeceğim (/ hatırlamıyor musunuz?) :global- IOW, beklediğim senaryo :subeşleşen satırlara uygulamaktı, sonra ien sonunda bir kez arttı. Bu çözümün biraz daha yavaş olmasını bekliyorum. Ama gerçekten önemli mi? Önemli olan, bellek + deneme ve hatadan çalışan bir çözümle ne kadar kolay gelebildiğimizdir. Örneğin, Vimgolfers makroları tercih ediyor.
Luc Hermitte

1
@LucHermitte evet aynısını savundum ve hızın önemi yok. Bence bu iyi bir cevap ve yine ondan bir şeyler öğrendim. Belki g/s//kapsam davranışı diğer kirli numaralara izin verir. Bu yüzden hem ilginç cevaplar hem de tartışma için teşekkür ederim, çoğu zaman bir cevap vermekten çok şey öğrenmiyorum =).
Doktor OSwaldo

4

Bu sayfada zaten üç harika cevap var, ancak Luc Hermitte'nin bir yorumda önerdiği gibi, bu kelepçeyi yapıyorsanız, önemli olan, çalışan bir çözüme ne kadar hızlı ve kolay bir şekilde ışık tutabileceğinizdir.

Bu nedenle, aslında hiç kullanamayacağım bir sorundur :substitute: düzenli normal mod komutları ve özyinelemeli bir makro kullanılarak kolayca çözülebilen bir sorundur :

  1. (Gerekirse) Önce kapatın 'wrapscan'. Kullanacağımız normal ifade, istenen sonuç metninin yanı sıra ilk metnin de eşleşeceğinden, 'wrapscan'açıkken makro aksi takdirde sonsuza kadar oynatmaya devam eder. (Ya da ne olduğunu anlayana ve düğmesine basın <C-C>.):

    :set nowrapscan
    
  2. Arama teriminizi ayarlayın (mevcut yanıtlarda daha önce belirtilen aynı temel düzenli ifadeyi kullanarak):

    /#\d\+\(\.\d\+\)\?<CR>
    
  3. (Gerekirse) GerektiğiN kadar tuşuna basarak ilk eşleşmeye geri dönün ,

  4. (Gerekirse) İlk eşleşmeyi istenen metne dönüştürün:

    cE#1<Esc> 
    
  5. "qKaydı temizleyin ve makro kaydetmeye başlayın:

    qqqqq
    
  6. Geçerli sayaç Yank:

    yiW
    
  7. Bir sonraki maça atla:

    n
    
  8. Mevcut sayacı az önce çektiğimiz sayaçla değiştirin:

    vEp
    
  9. Sayacı artır:

    <C-A>
    
  10. Makroyu oynat q. "q5. adımda temizlediğimiz için kayıt hala boş, bu nedenle bu noktada hiçbir şey olmuyor:

    @q
    
  11. Makroyu kaydetmeyi durdur:

    q
    
  12. Yeni makroyu oynayın ve izleyin!

    @q
    

Tüm makrolarda olduğu gibi, yukarıda açıkladığım gibi birçok adım gibi görünüyor, ancak bunları gerçekten yazmanın benim için çok hızlı olduğunu unutmayın : özyinelemeli makro kayıt-kaynatma plakası dışında hepsi sadece normal düzenleme komutları Düzenleme sırasında her zaman gerçekleştiriyorum. Düşünmeye yaklaşan bir şey yapmak zorunda kaldığım tek adım , aramayı gerçekleştirmek için düzenli ifadeyi yazdığım 2. adımdı.

İki komut satırı modu komutları ve tuş vuruşlarını bir dizi olarak biçimlendirilmiş, çözümün bu tip hız daha netleşiyor: Bunu yazabilirsiniz gibi ben kadar hızlı hemen hemen aşağıdaki hokkabaz 1 :

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

Muhtemelen bu sayfadaki diğer çözümleri biraz düşünerek ve belgelerin 2 referansıyla ortaya çıkabilirdim , ancak makroların nasıl çalıştığını anladıktan sonra, genellikle düzenlediğiniz hızda çalkalamak gerçekten kolaydır.

1: Orada olan makro daha fazla düşünülmesi gereken durumlar ama pratikte pek gelmiyorsun bulabilirsiniz. Ve genellikle ortaya çıktıkları durumlar, bir makronun tek pratik çözüm olduğu durumlardır.

2: Diğer cevaplayıcıların çözümlerini benzer şekilde kolayca bulamayacakları anlamına gelmez: sadece kişisel olarak parmak uçlarımda kolayca sahip olmadığım beceri / bilgiye ihtiyaç duyarlar. Ancak tüm Vim kullanıcıları düzenli düzenleme komutlarının nasıl kullanılacağını biliyor!


1

Sonuna '#' artı bir 'c' sayacı ekleyerek

:let c=0 | g/^#\d\+.*/ let c+=1 | s//\='#' . c

Global kısım g/^#\d\+.*/ let c+=1, sayacı sadece desen içeren satırlarda artırmamıza izin verir


Hippietralarla kaplı olanlar cevap vermiyor mu?
D. Ben Knoble

Bu durumda, benzer bir şey yapmanın daha kısa bir yolunu bulduğumu düşünüyorum, belki bir yorum daha iyi olurdu.
SergioAraujo
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.