vim 정규식 대체 결정

vim 정규식 대체 결정

작년에 저는 Vimwiki를 사용하여 프로젝트의 주간 진행 상황을 기록하기 시작했습니다. 내 주간 위키 링크 목록의 형식은 시간이 지남에 따라 약간 변경되었습니다. 연말에 나는 색인 페이지를 잠깐 살펴보고 내가 만들고 있던 주요 항목의 형식을 통합하기로 결정했지만 정규식을 제대로 얻을 수 없었습니다.

업데이트하려는 글머리 기호의 원래 예는 내가 원하는 형식으로 위의 최신 항목과 함께 아래에 표시됩니다.

 * [[2018_Week_25|Week 25, 17th through the 23rd June]]
 * [[2018_Week_24|Week 24, 10th through 16th June]]
 * [[2018_Week_23|Week 23, 3rd through 9th June]]
 * [[2018 Week 22|Week 22, 27th May through 2nd June]]
 * [[2018 Week 21]], 20th through 26th May
 * [[2018_Week_20]]
 * [[2018_Week_19]]
 * [[2018_Week_18]], 29th April through 5th May
 * [[2018_Week_17]], 22nd through 28th April
 * [[2018_Week_16]], 15th through 21st April
 * [[2018_Week_15]], 8th through 14th April
 * [[2018_Week_14]], 1st through 7th April
 * [[2018_Week_13]], 25th through 31st March

나는 간단한 일치로 시작했습니다.

/\[\[\d+[_\s]Week[_\s]\d+\]\],\s\d+\w+.*/g

5, 8-13행의 해당 부분과 일치합니다. 그런 다음 일부 패턴 변수와 대체 항목을 추가하려고 시도했지만 모든 것이 무너졌습니다. 다음 대체 줄을 사용하면 Vim은 갑자기 이전에 찾은 패턴을 더 이상 찾지 못한다고 결정합니다.

:1,13s/\(2018[_\s]Week[_\s]\d\d\),\s\(\d+\w+\)/\[\[\1|\1\2\]\]/g
E486: Pattern not found: \(2018[_\s]Week[_\s]\d\d\),\s\(\d+\w+\)

나는 실제로 이것에 대한 미묘한 변형을 많이 시도했지만, 내가 단지 명백한 것을 간과하고 있다고 믿기 시작했습니다. 누구든지 어떤 제안이 있습니까?

답변1

:%s/\(\[\[\d\+[_ ]\+Week\([_ ]\+\)\(\d\+\)\)\]\],\(.*\)/\1|Week\2\3,\4]]/

\s*수동으로 입력한 텍스트에서 항상 발생하는 불일치를 더 잘 포착하기 위해 적절한 곳에 패딩을 추가하여 이 표현식을 개선 할 수 있습니다 .

제안된 솔루션에는 몇 가지 문제가 있습니다.

  • 정규식: 다음 \(2018[_\s]Week[_\s]\d\d\),\s\(\d+\w+\) 과 같은 이유로 일치하지 않습니다.

    • 백슬래시로 이스케이프된 사전 정의 문자 클래스는 로 구분된 사용자 정의 문자 클래스 내에서 사용할 수 없습니다 []. [_\s]밑줄, 백슬래시 또는 s문자와 일치합니다. _\|\s이러한 상황에서 사용할 수 있습니다 .
    • +"1 이상" 수량자가 활성화되어 있으므로 특별한 의미를 위해 이 문자를 이스케이프해야 합니다. 그렇지 않으면 +리터럴 기호와 일치합니다.
    • 섹션 앞에는 일치시킬 텍스트의 시퀀스 일치가 있지만 ,\s\(\d+\w+\)해당 시퀀스 일치가 패턴에서 누락되었습니다.\]\]\]\]
  • 문자열에서 백슬래시를 바꾸는 문제를 무시하고 결과 문자열을 종료하여 종료하려고 ]]하지만 지정된 쉼표 뒤의 날짜와 일치하는 부분만 사용합니다 \d\+\w\+. 즉, 교체가 성공하면 줄이 중간 어딘가에서 줄을 종료해야 하는 시퀀스 29th]] April through 5th May와 함께 다음과 같은 텍스트로 끝나게 됩니다.]]

  • 대체 문자열: \[\[\1|\1\2\]\] 정규 표현식이 아니므로 [및 같은 문자를 ]이스케이프할 필요가 없습니다.

  • 또한 잘못된 것은 아니지만 모든 것이 이미 포함되어 있고 표현식의 앞부분을 사용하여 컨텍스트를 지정하는 방식으로 \d\+\w\+중복되므로 항상 etc와 일치 하고 잘못된 콘텐츠와 일치하지 않습니다.\w\d9th

편집: @user1133275의 매우 좋은 제안은 (일부 변경 사항 포함) 원본 솔루션의 캡처 그룹에 쉼표를 사용하는 것입니다. 이는 날짜 간격이 지정되지 않은 행도 변경합니다. "x번째에서 y번째"는 없습니다.

:%s/\(\[\[\d\+[_ ]\+Week\([_ ]\+\)\(\d\+\)\)\]\]\(,.*\)\?/\1|Week\2\3\4]]/

@ user1133275는 답변을 제공하지 않았으므로 토론 결과를 이 답변의 댓글 섹션에 넣겠습니다. 그들이 그것을 답변에 넣기로 결정하고 나에게 통보되면 이 편집 내용을 제거하여 기본 아이디어 작성자에게 크레딧이 돌아가도록 하겠습니다.

답변2

귀하의 질문을 올바르게 이해했다면 다음 대체 방법으로 원하는 작업을 수행해야 합니다.

%s/\[\[\(\d\+\)\([_ ]\)Week\([_ ]\)\(\d\+\)\]\],\(\s\d\+\w\+.*\)/[[\1\2Week\3\4|Week \4,\5]]/

참고: \([_ ]\)캡처 그룹은 이전 구성 요소에 나타나는 구분 기호(공백 또는 밑줄)를 유지합니다 |. 구분 기호는 5행의 공백이고 밑줄은 8-13행에서 사용됩니다.

답변3

vim 정규 표현식은 비표준이므로 vim에서 업계 최고의 perl을 사용하세요.

:%!perl -pe '$RE'

vim 외부에서 테스트할 수 있습니다.

> echo "[[2018_Week_18]], 29th April through 5th May" \
| perl -pe 's/[_ ](Week)[_ ](\d+)\]\](, .*)?/_$1_$2|$1 $2$3]]/g'
[[2018_Week_18|Week 18, 29th April through 5th May]]

Perl RE는 vim RE 길이의 약 1/2일 뿐만 아니라 Perl RE는 다른 많은 도구(grep/rename/vim/sed/awk/etc)와도 복사/붙여넣기와 호환됩니다.

관련 정보