명령줄에서 (중첩된) 텍스트 따옴표 제거

명령줄에서 (중첩된) 텍스트 따옴표 제거

명령줄에서 많은 양의 텍스트를 구문 분석하고 모든(중첩된) 텍스트 따옴표를 공백으로 바꿔야 합니다. 따옴표는 특정 구문으로 표시됩니다: [quote=username]quoted text[/quote].

중첩된 따옴표가 있는 입력 예는 다음과 같습니다.

text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3

예상되는 출력은 다음과 같습니다.

text part 1   text part 2   text part 3

의 도움으로이 문제어떻게든 작동하게 했지만(위의 출력을 얻었습니다) sed ':b; s/\[quote=[^]]*\][^[\/]*\[\/quote\]/ /g; t b'중간 부분( ]에는 따옴표에 또는 같은 문자가 [^[\/]포함될 수 있기 때문에 문제가 있습니다 .[]

즉, sed입력이 예를 들어 다음과 같은 경우 내 명령이 작동하지 않습니다.

text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [foo] [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3

한 가지 문제는 sed탐욕스럽지 않은 한정자를 지원하지 않는 것 같아서 가능한 가장 긴 일치 항목이 항상 입력에서 캡처된다는 것입니다. 다루기가 어렵습니다ㅏ)사용자 이름 및비)일반 인용문.

나는 또한 이것이 sed이 문제에 대한 최선의 도구가 아니며 그런 일을 수행하지 못할 수도 있다고 생각합니다. 예를 들어 아마도. perl아니면 awk더 잘 작동할 수 있을까요?

이제 마지막 질문은 이 문제를 해결하는 가장 좋고 효율적인 방법은 무엇입니까?

답변1

입력에 <또는 >문자가 포함되어 있지 않다는 것을 알고 있는 경우 다음을 수행할 수 있습니다.

sed '
  # replace opening quote with <
  s|\[quote=[^]]*\]|<|g
  # and closing quotes with >
  s|\[/quote\]|>|g
  :1
    # work our way from the inner quotes
    s|<[^<>]*>||g
  t1'

<또는 문자가 포함될 수 있는 경우 >다음과 같은 구성표를 사용하여 이스케이프할 수 있습니다.

sed '
  # escape < and > (and the escaping character _ itself)
  s/_/_u/g; s/</_l/g; s/>/_r/g

  <code-above>

  # undo escaping after the work has been done
  s/_r/>/g; s/_l/</g; s/_u/_/g'

AND perl, 재귀 정규식 사용:

perl -pe 's@(\[quote=[^\]]*\](?:(?1)|.)*?\[/quote\])@@g'

아니면 당신이 언급한 것처럼:

perl -pe 's@(\[quote=.*?\](?:(?1)|.)*?\[/quote\])@@g'

를 사용하면 perl옵션을 추가하여 여러 줄 입력을 처리할 수 있습니다 -0777. 의 경우 sed코드 앞에 다음 접두사를 추가해야 합니다.

:0
$!{
  N;b0
}

그러면 전체 입력이 패턴 공간에 로드됩니다.

답변2

나는 이것을 확인했고 그것은 나를 위해 일했습니다. 대신 다른 임시 모드를 선택할 수도 있습니다 foobar. 이 모드가 없으면 sed태그 사이의 모든 항목이 제거되고 하나만 남습니다.text part 1 text part 3

sed -e 's/\/quote\]/foobar\]/3' -e 's/\[.*\/quote\]//' -e 's/\[.*foobar]//' testfile

대신 testfile에 파이프할 수 있다면cat

답변3

모든 시작 인용문에서 카운터 변수를 증가시키고 모든 닫는 인용문에서 카운터 변수를 감소시키는 작은 스크립트입니다. 카운터 변수가 더 크면 0텍스트 조각을 건너뜁니다.

#!/bin/bash

# disable pathname expansion
set -f    
cnt=0
for i in $(<$1); do
        # start quote
        if [ "${i##[quote=}" != "$i" ] && [ "${i: -1}" = "]" ]; then
                ((++cnt))
        elif [ "$i" = "[/quote]" ]; then
                ((--cnt))
        elif [ $cnt -eq 0 ]; then
                echo -n "$i "
        fi
done
echo

산출:

$ cat q1
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
$ ./parse.sh q1
text part 1 text part 2 text part 3
$ cat q2
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [foo] [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
$ ./parse.sh q2
text part 1 text part 2 text part 3

답변4

POSIX sed여기의 자세한 지침에 따라 이 작업을 수행 할 수 있습니다 . 이 솔루션은 표시된 두 입력 모두에 적용됩니다. 필요한 변환을 달성하기 위해 줄 바꿈을 마커로 사용하기 때문에 입력 제한은 여러 줄이 아닙니다.

$ sed -e '
      :top
      /\[\/quote]/!b
      s//\
&/
      s/\[quote=/\
\
&/

     :loop
        s/\(\n\n\)\(\[quote=.*\)\(\[quote=.*\n\)/\2\1\3/
     tloop

     s/\n\n.*\n\[\/quote]//
     btop
 '  input.txt

관련 정보