![Sed - 두 문자열을 바꾸면서 그 사이의 내용을 유지하는 방법은 무엇입니까?](https://linux55.com/image/227058/Sed%20-%20%EB%91%90%20%EB%AC%B8%EC%9E%90%EC%97%B4%EC%9D%84%20%EB%B0%94%EA%BE%B8%EB%A9%B4%EC%84%9C%20%EA%B7%B8%20%EC%82%AC%EC%9D%B4%EC%9D%98%20%EB%82%B4%EC%9A%A9%EC%9D%84%20%EC%9C%A0%EC%A7%80%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
일부 DokuWiki 페이지를 MediaWiki 형식으로 변환하는 쉘 스크립트를 작성 중입니다.그 반대로. 각주에 문제가 있습니다.
DokuWiki에는 DokuWiki의 기본 각주 마크업에 확장 기능을 추가하는 플러그인이 있습니다. 그 중 하나는 메모에 이름을 추가하고 나중에 다시 사용할 수 있는 기능입니다. 예를 들어:
도쿠위키 | 미디어 위키 |
---|---|
[(FOO>This is a footnote.)] |
<ref name="FOO">This is a footnote.</ref> |
[(BAR>Another note in the same paragraph.)] |
<ref name="BAR">Another note in the same paragraph.</ref> |
그리고sed쉽게 찾아 교체할 수 있습니다. "주석 이름"이 있는 각주와 관련된 내 스크립트 명령은 다음과 같습니다.
sed -ri 's@\[\(.*>@<ref name=\"XXX\">@g' dokuwiki-page.txt
sed -ri 's@\)\]@<\/ref>@g' dokuwiki-page.txt
그러나 물론 이름은 유지되지 않고 해당 이름이 있는 모든 주석에 새로운 일반 주석 이름 "XXX"를 적용할 뿐입니다. 따라서 위의 예에서 결과는 다음과 같습니다.
도쿠위키 | 미디어 위키 |
---|---|
[(FOO>This is a footnote.)] |
<ref name="XXX">This is a footnote.</ref> |
[(BAR>Another note in the same paragraph.)] |
<ref name="XXX">Another note in the same paragraph.</ref> |
주석 이름(예제에서는 FOO 및 BAR)을 유지하는 데 도움이 필요합니다.나는 단지 다른 해결책을 받아들이는 것이 아닙니다.sed.
중요 사항:
- 각주 문장은 단락 중간에 나타날 수 있으며, 각주 이름이 있는 여러 참조는 같은 단락에 다른 이름으로 나타날 수 있습니다. (일명 Unix의 "매우 긴 줄" 단락)
- MediaWiki 마크업이 너무 많은 html 태그( sums 로 가득 차 있음 ) 를 사용하기 때문에 명령을 분할하여
[(
첫 번째 명령에서 바꾸고 두 번째 명령에서 바꿀 수 없습니다 . 태그가 잘못 교체되었을 수 있습니다.>
<
>
- 내부
[(...)]
가 없는 것도 있습니다 . 대신에>
in처럼요 .[(This is a nameless note.)]
[(My_Note_Name>This is a named note.)]
답변1
perl
탐욕스럽지 않은 반복 연산자와 함께 정규식을 사용하면 이런 종류의 작업이 훨씬 쉽습니다.
perl -i -pe 's{\[\((.*?)>(.*?)\)\]}{<ref name="$1">$2</ref>}g' your-file
-i
및 는 -r
비표준 sed
옵션입니다. -i
실제로 perl
는 서로 호환되지 않는 방식이지만 일부 구현에 의해 복사됩니다.
perl
여러 sed
구현과 달리 줄 크기에도 제한이 없고 NUL 문자를 처리할 수 있으며 기본적으로 입력을 바이트 단위로 처리하므로 사용자의 로케일에서 텍스트로 디코딩할 수 없는 입력의 문제가 없습니다.
입력 중 일부에 가 [(...)]
포함되어 있지 않을 가능성이 있는 경우 >
정규식을 조정해야 합니다. 참조 레이블에 w
ord 문자(ASCII 숫자 및 밑줄)만 포함된 경우 다음과 같을 수 있습니다.
perl -i -pe 's{\[\((\w+)>(.*?)\)\]}{<ref name="$1">$2</ref>}g' your-file
또 다른 방법은 모든 항목을 찾아 [(...)]
별도의 단계로 바꾸는 것입니다.
perl -i -pe '
s{\[\(.*?\)\]}{
$& =~ s{\[\((.*?)>(.*)\)\]}{<ref name="$1">$2</ref>}r
}ge' your-file
또한 다음을 사용하여 이름 없는 주석을 변경할 수도 있습니다 <ref>nameless</ref>
.
perl -i -pe '
s{\[\(.*?\)\]}{
$& =~ s{\[\((?:(.*?)>)?(.*)\)\]}{
"<ref" . (defined($1) ? qq( name="$1") : "") . ">$2</ref>"
}re
}ge' your-file
[(...)]
또는 포함되지 않은 항목과 일치하는지 확인하려면 부정 예측 연산자를 사용하세요 )]
.
perl -i -pe 's{\[\(((?:(?!\)\]).)*?)>((?1))\)\]}{<ref name="$1">$2</ref>}g' your-file
답변2
최종 SED 방법:
나는 다음을 사용하여 해결책을 찾았습니다.sed및 정규식 그룹.
sed -Ei 's@\[\(([[:alnum:]_-]*)>([[:alnum:][:space:].!?:;,@#%$&<>-_]*)\)\]@<ref name=\"\1\">\2<\/ref>@g' dokuwiki-page.txt
설명하다:
[(
+letters, numbers, underscores and dashes in any quantity
+>
+letters, numbers, spaces and punctuation
+ 로 줄 찾기)]
- 그룹 1: 문자, 숫자, 밑줄, 대시를 원하는 수만큼 사용할 수 있습니다.
- 그룹 2: 문자, 숫자, 공백 및 대부분의 구두점을 사용할 수 있습니다. 어떤 이유로
[:punct:]
이것은 잘 작동하지 않으며 큰 목록을 사용해야 합니다:.!?:;,@#%$&<>-_
. - 여기서의 비결은
\1
그룹을 사용하거나 참조 할 수 있다는 것입니다\2
. 변수에 저장하는 것과 같습니다. - 다른 항목이 포함되어 있기 때문에
.*
대신 사용할 수 없습니다 . 따라서 동일한 단락에 다른 이름의 각주(일명 매우 긴 줄)가 있는 경우 정규식에는 첫 번째 각주부터 두 번째 각주 내용 끝까지 모든 내용이 포함됩니다. 정말 엉망이야!([[:alnum:]_-]*)
>
- 이들 모두를
<ref name="
+group \1
+">
+group \2
+ 로 바꾸십시오</ref>
.- 여기서는 주변 콘텐츠를 교체하는 동안 유지하려는 콘텐츠를 역참조
\1
하고 사용합니다 .\2
- 여기서는 주변 콘텐츠를 교체하는 동안 유지하려는 콘텐츠를 역참조
매우 매우 어렵습니다! 이 작업을 수행하는 방법을 알아내는 데 3일이 걸렸습니다. 그리고 너무 길어요. Perl을 선택하는 것이 좋습니다. 하지만 sed를 사용하는 더 쉬운 방법을 알고 계시다면 저에게 가르쳐 주세요. 저는 배우는 것을 좋아합니다!
읽기 제안:
- 도허티, D., & 로빈스, A. (1997). SED 및 AWK. (두번째 버전). 오라일리.