2014-11-04 59 views
3

我正嘗試使用vim將分層(xml)文件重新格式化爲「每行」文件。從範圍多行vim正則表達式替換

這是一個簡化的例子。真實情況是「大」(500k行),條目和組是任意計數。

輸入文件:

<group key="abc"> 
    <entry val="1"/> 
    <entry val="2"/> 
    <entry val="3"/> 
</group> 
<group key="xyz"> 
    <entry val="1"/> 
    <entry val="2"/> 
    <entry val="3"/> 
    <entry val="4"/> 
    <entry val="5"/> 
</group> 

輸出結果:

abc,1 
abc,2 
abc,3 
xyz,1 
xyz,2 
xyz,3 
xyz,4 
xyz,5 

請注意,我並不需要一個魔法表情,做了這一切(儘管這會是膨脹)。我正在努力的部分是獲得與每個條目相關的關鍵。我確信處理這個問題有一個很好的習慣用法。提前致謝。

有一兩件事我想,可能是有用的人如下:

:g/key="\(.*\)"/.;/<\/group/s/<entry /\1,<entry /g 

因爲範圍匹配不結轉到替代不工作。這個表達式本質上是尋找pat1,從那裏建立一個範圍到pat2,然後用pat4替換pat3(但只在pat1,pat2範圍內)。

​​

解決方案

下最好的解決辦法解決它通過查找條目,然後向後爲重點,而不是什麼,我試圖通過建立一個範圍和多個取代上面做。什麼最終工作需要一些小的修改,所以他們在這裏提供給其他人。該做繁重的命令是:

:g/entry/?key?,\?t. 
:g/entry/norm ddpkJ 
:v/entry/d 

擊穿:

搜索所有的輸入行:

:g/entry/ 

從那裏開始,向後搜索具有關鍵線路和在每個條目下面複製它。

?key?,\?t. 

再次搜索所有入境線,並切換到普通模式的編輯

:g/entry/norm 

交換兩行(刪除鍵行並將其粘貼到組線以下)。向上移動到關鍵線並加入兩條線。

ddpkJ 

一旦所有鍵被映射,搜索任何沒有條目並刪除它們的行。

:v/entry/d 

如果您像我一樣有多個層次結構,則可以多次運行前兩行。一旦所有東西都在一條線上,將它清理成任何最終格式都是非常簡單的。另一個主要的好處是,該解決方案可以放在容易的腳本,然後重新運行與

vim -S script.vim data.file 
+0

一個偉大的特技我發現,幾乎得到我開始是表達式: :克/ <組密鑰= 「\(* \)」 /.;/<\/組/秒/ < entry/\ 1, JHiant 2014-11-04 23:32:50

+0

只要把你在這個問題上嘗試的東西。 (格式會讓它看起來更好) – FDinoff 2014-11-04 23:41:01

+0

謝謝@FDinoff。完成。 (第一篇文章) – JHiant 2014-11-04 23:47:29

回答

1

繼將工作

:g/entry/?<group?,?<group?t. 
:%norm J 
:g/<\//d 
:%norm df"f"df"i,<C-v><Esc>f"d$ 

擊穿

對於含有entry每一行,向後爲<group搜索和複製到line entry below

:g/entry/?<group?,?<group?t. 

<group key="abc"> 
    <entry val="1"/> 
<group key="abc"> 
    <entry val="2"/> 
<group key="abc"> 
    <entry val="3"/> 
<group key="abc"> 
</group> 
<group key="xyz"> 
    <entry val="1"/> 
<group key="xyz"> 
    <entry val="2"/> 
<group key="xyz"> 
    <entry val="3"/> 
<group key="xyz"> 
    <entry val="4"/> 
<group key="xyz"> 
    <entry val="5"/> 
<group key="xyz"> 
</group> 

加入所有行

:%norm J 

<group key="abc"> <entry val="1"/> 
<group key="abc"> <entry val="2"/> 
<group key="abc"> <entry val="3"/> 
<group key="abc"> </group> 
<group key="xyz"> <entry val="1"/> 
<group key="xyz"> <entry val="2"/> 
<group key="xyz"> <entry val="3"/> 
<group key="xyz"> <entry val="4"/> 
<group key="xyz"> <entry val="5"/> 
<group key="xyz"> </group> 

刪除結束標記

:g/<\//d 

<group key="abc"> <entry val="1"/> 
<group key="abc"> <entry val="2"/> 
<group key="abc"> <entry val="3"/> 
<group key="xyz"> <entry val="1"/> 
<group key="xyz"> <entry val="2"/> 
<group key="xyz"> <entry val="3"/> 
<group key="xyz"> <entry val="4"/> 
<group key="xyz"> <entry val="5"/> 

修正通過搜索和刪除,並從報價剩餘的文本。 請注意,<C-v><Esc>是在命令中添加轉義的關鍵序列。

:%norm df"f"df"i,<C-v><Esc>f"d$ 

abc,1 
abc,2 
abc,3 
xyz,1 
xyz,2 
xyz,3 
xyz,4 
xyz,5 
+0

你可以分解?pat?,?pat?t。範圍表達? – JHiant 2014-11-05 14:31:48

+0

而不是:%norm J依賴於文件的完美平衡,我做了:g/entry/norm kJ找到所有的入口行,用粘貼的組移動到上面的行並加入它們。這支持多個級別。 – JHiant 2014-11-05 14:53:11

+0

最佳答案,因爲它巧妙地顛倒了我正在做的搜索替換。對於有額外層次結構的情況,這也很有效。一旦我在一行中獲得了所需的所有數據,只需:%grep條目清除了其他所有內容。然後它只是%s/junk /,/直到完成。謝謝! – JHiant 2014-11-05 14:59:58

1

那麼,這是不是一個神奇的一個線,但可能工作:一步

ggqq/groupf"lyi"<c-v>n0I<c-r>"<esc>ddnddq 
[email protected] 
:%s/\s*<entry val="/,/g 
:%s/"\/>//g 

步驟:

gg  => Go to the top 
qq  => Record a macro called q 
/group => Search for "group" 
f"l  => Go to the key 
yi"  => Copy the key 
c-v  => Vertical visual mode 
n0  => Go to the end of the "group", place the cursor at the beginning 
I<c-r>"<esc> => Paste at the beginning 
dd  => Delete <group> line 
ndd  => Delete end </group> line 
q  => Stop macro 

[email protected] => Play macro 100 times, use whatever you need 

現在你應該有這樣的:

abc <entry val="1"/> 
abc <entry val="2"/> 
abc <entry val="3"/> 
xyz <entry val="1"/> 
xyz <entry val="2"/> 
xyz <entry val="3"/> 
xyz <entry val="4"/> 
xyz <entry val="5"/> 

然後,只需清洗你不需要的東西:

:%s/\s*<entry val="/,/g 
:%s/"\/>//g 
+0

感謝您的解決方案。 qq宏的成語是我一段時間沒用過的東西。由於它是交互式的,因此適用於中等和小型文件。我將不得不在vim之外進行大量的行計數工作,但是要弄清楚爲一個非常大的文件重播宏的次數。 – JHiant 2014-11-05 15:42:11