2017-02-15 110 views
2

我有一些文本,其中有兩列和兩個或更多的行。第一列名稱只打印一次。之後,它在後續行中留空,直到它再次更改。Vim搜索並替換可變行數

例如

name1 xxx 
     zza 
     yyy 
     zzz 
name2 ggg 
     xxx 
name3 xxx 
     zza 
     ggg 
     yyy 
     zzz 

我想更改上述各行打印的列名,如下所示:

name1 xxx 
name1 zza 
name1 yyy 
name1 zzz 
name2 ggg 
name2 xxx 
name3 xxx 
name3 zza 
name3 ggg 
name3 yyy 
name3 zzz 

注:在開始提到的,線條與空白的第一列中的數字是變量。可以是任意數量的上述2

以下方式將工作,如果反覆應用:

:%s/\(^\S\+ \)\(.*\n\)\s\+/\1\2\1/ 

不過,當然,這隻會更改一行的時間,我必須重複,直到所有比賽已更新。

我的問題:是否有一個命令來完成上述轉換的行數是可變的。

+0

而不是'%',您可以指定要操作的行號。 例如:':12,16s/toto/titi/g' – Coconop

回答

1

你的模式幾乎是工作,主要的問題是,既然你 更換這改變了線換行,這就是爲什麼你需要正如你所描述的,運行多次。當你刪除下一行時,光標將跳過它(即使它被替換回來),然後你不能匹配。

只需在相關的 部分「開始」匹配,使用\zs標誌非常有用,您可以輕鬆解決此問題。 \v是 也可用於使模式更具可讀性,控制魔術 選項。這應該工作:

:%s/^\v(\S+\s+).*\n\zs\s+/\1 

它捕獲的非空白部分,移動到下一個空行開始和 並將匹配存在。然後替換捕獲的部分。現在當光標移動時,將重複該過程,並且如果以下行 未開始空白(例如在新組的開始處),則 沒有任何反應,因爲它不匹配。

0

您可以將相同的邏輯記錄到宏,在這種情況下q。

qq:%s/\(^\S\+ \)\(.*\n\)\s\+/\1\2\1/按回車鍵並再次q要停止錄製宏

@q將再次運行它,但如果你知道行的最大數量(例如:10),你可以@●運行10

+0

4 @ q將解決您的問題。 1000 @ q這樣的高數字也沒有什麼壞處。它仍然會做你想要的。 – arithran

+1

謝謝。我使用宏來重複發出命令。請參閱sidyll回答一個命令。 – sankoz

0

使用awk這可能是一個解決方案:

:%!awk '{if($2==""){$2=$1;$1=name}else{name=$1};print}' 
0

你可以用這個小Python腳本解決這個問題,提供了所有的空白都是空格,而不是標籤:

關口。PY

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import fileinput 

for line in fileinput.input(): 
    if not line.startswith(" "): 
      current = line.split()[0] 
      print(line, end="") 
      continue 
    print(line.replace(" " * len(current), current, 1), end="") 

然後通過管道將文本文件的腳本:

python col.py < text.txt 

Vim可以用Python的支持下重新編譯,所以這樣的事情可能在Vim內部使用。