2014-11-04 1 views
3

vim을 사용하여 계층 적 (xml) 파일을 "per line"파일로 다시 포맷하려고합니다.multiline 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 

I (즉 팽창 될 거라고하지만)이 모든 것을 수행하는 하나의 마법 식을 필요는 없습니다. 내가 고민하는 부분은 각 항목과 관련된 키를 얻는 것입니다. 나는 이것을 처리하는 좋은 관용구가있을 것이라고 확신한다. 미리 감사드립니다. 다음과 같이 내가 노력하고 다른 사람에게 유용 할 수 있습니다

한 가지입니다 : 범위 일치 대체를 이월되지 않기 때문에 작동하지 않습니다

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

. 이 표현식은 근본적으로 pat1을 찾고 거기에서 pat2까지의 범위를 만든 다음 pat3을 pat4로 대체합니다 (단, pat1, pat2 범위의 인스턴스 내에서만 가능).

:g/pat1/.;/pat2/s/pat3/pat4/g 

솔루션

가장 좋은 방법은 아래 나는 범위와 여러 대체를 구축하여 위의 일을하려고 있었는지 반대로 키 위해 뒤로 다음 항목에 대한보고하여 해결했다. 마지막으로 약간의 수정이 필요했기 때문에 다른 사람들을 위해 여기에 제공됩니다. 무거운 작업을 수행하는 명령은 다음과 같습니다

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

내역 : 모든 항목 라인을위한

검색 : 거기에서

:g/entry/ 

키를 가지고있는 라인을 위해 뒤쪽으로 검색 그것을 각 항목 아래에 복사하십시오. 일반 모드 편집에

?key?,\?t. 

다시 모든 항목 라인에 대한 검색 및 스위치

:g/entry/norm 

스왑 두 줄 (키 줄을 삭제하고 그룹 라인 아래에 붙여 넣습니다). 키 라인까지 이동하고 두 라인을 결합하십시오.

ddpkJ 

모든 키가 매핑되면 항목이없는 모든 행을 검색하고 삭제하십시오.

:v/entry/d 

내가하는 것처럼 여러 계층이있는 경우 처음 두 줄을 여러 번 실행할 수 있습니다. 일단 모든 것이 한 줄에 있다면, 최종 형식이 무엇이든간에 그것을 정리하는 것은 매우 간단합니다.

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

단계 단계에서 :이 솔루션은

vim -S script.vim data.file 
+0

한 위대한 속임수 내가 나를 거의가 시작됩니다 발견은 표현이다 entry/\ 1, JHiant

+0

질문에 시도한 것을 넣으십시오. (서식을 지정하면 더 좋아 보이게됩니다.) – FDinoff

+0

Thanks @FDinoff. 끝난. (첫 번째 게시물) – JHiant

답변

1

다음, entry을 포함하는 각 라인에 대한

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

고장

작동 <group 위해 뒤쪽으로 검색하고 복사 할 엔트리 아래의 라인

: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>은 명령에 이스케이프를 추가하는 주요 순서입니다. : g/<그룹 키 = "\ (* \.)"/.;/<\/ 그룹/S/<

:%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

+0

대신에 % norm J는 완벽하게 균형 잡힌 파일에 의존합니다. 모든 입력 행을 찾고 위에 붙여진 그룹으로 이동하여 조인합니다. 이것은 하나 이상의 레벨을 지원합니다. – JHiant

+0

우수 답변, 독창적 인 검색 반전 때문에 내가하고 있던 바꾸기. 이것은 또한 추가적인 계층 구조가있는 경우에도 효과적이었습니다. 한 줄에 필요한 모든 데이터를 얻었 으면 % grep 항목을 사용하여 다른 모든 항목을 지 웁니다. 그런 다음 % s/junk /,/완료 될 때까지입니다. 감사! – JHiant

1

음으로 쉽게 스크립트를 다시 실행에 넣어 될 수 있다는 또 다른 주요 이점은,이 마법의 한 줄이 아니라 작동 할 수있다

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"/> 
:
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 

이제 뭔가를해야한다 617,451,515,

그럼 그냥 필요없는 것을 정리 :

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

솔루션을 가져 주셔서 감사합니다. qq 매크로 관용구는 잠시 사용하지 않은 것입니다. 대화 형이기 때문에 중간 및 작은 파일에 적합합니다. 매우 큰 파일에 대해 매크로를 재생할 횟수를 파악하기 위해 vim 외부에서 많은 선 계산 작업을해야했습니다. – JHiant