Sed: 텍스트의 모든 단어에서 첫 번째가 아닌 모든 단어 반복을 수정합니다.

Sed: 텍스트의 모든 단어에서 첫 번째가 아닌 모든 단어 반복을 수정합니다.

비슷한 작업을 수행하려면 sed를 사용해야 합니까?

qq    ab xyz     ab qq aa ab 

이 되다:

qq    ab xyz     +ab+ +qq+ aa +ab+

답변1

입력에 <, >또는 +문자가 모두 포함되어 있지 않으면 다음을 수행할 수 있습니다.

sed '
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g'

다음과 같은 경우 언제든지 이 문제를 피할 수 있습니다.

sed '
  s/:/::/g;s/</:{/g;s/>/:}/g
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g
  s/:}/>/g;s/:{/</g;s/::/:/g'

이는 각 행에서 독립적으로 이 작업을 수행한다고 가정합니다. 전체 파일에 대해 이 작업을 수행하려면 먼저 전체 파일을 메모리에 로드해야 합니다(일부 sed구현에는 크기 제한이 있음).

sed '
  :2
  $!{N;b2
  }
  s/:/::/g;s/</:{/g;s/>/:}/g
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g
  s/:}/>/g;s/:{/</g;s/::/:/g'

그러나 이는 매우 비효율적이며 사용하기가 훨씬 쉽습니다 perl.

perl -pe 's/\w+/$seen{$&}++ ? "+$&+" : $&/ge'

라인 기반:

perl -pe 'my %seen;s/\w+/$seen{$&}++ ? "+$&+" : $&/ge'

답변2

또 다른 접근 방식은 다음과 같습니다. 이는 일부 seds를 사용합니다.

an='[:alnum:]' esc=$(printf '\033\[')
sed "/[${an}]/!d;=;a\ }
    s/.*/ & /;s/[^${an}]\{1,\}/   /g
    s| \([${an}"']\{1,\}\) | \
    s/\\([^+'"${an}"']\\)\\(\1\\)\\([^+'"${an}"']\\)/\\1+\\2+\\3/2|g
' <text |
sed '/^ /!N;s/\n */{/' |
sed -e 's/.*/ & /;s/+/ & /g' \
    -f - \
    -e "s/ //;s/ $//
        s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
        s/ + /+/g" text

기본적으로 처음 두 sed팀은 함께 협력하여 세 번째 스크립트를 작성했습니다. 첫 번째는 sed각 줄에서 영숫자 문자를 제외한 모든 항목을 지우고 줄이 없는 줄은 완전히 건너뜁니다. 나머지 모든 문자 그룹에 대해 대체 문을 작성하고 세 번째 문자는 끝납니다.(거의 즉시)스크립트를 읽고 해석하세요.

두 번째 스크립트는 sed첫 번째 스크립트가 한 줄씩 작성되기 때문에 필요하며 한 줄에 여러 개의 명령문이 있을 수 있습니다 s///. 첫 번째는 영숫자가 포함된 각 줄의 줄 번호를 인쇄하지만 세 번째의 함수 컨텍스트 내에서 쌍을 이루어야 하므로 sed두 번째가 그렇게 합니다.

다음은 예제 스크립트입니다:

...
43{
    s/\([^+[:alnum:]]\)\(n\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(N\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(G\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }
44{
    s/\([^+[:alnum:]]\)\(b\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(block\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }
45{
    s/\([^+[:alnum:]]\)\(END\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(SEDSCRIPT\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }

2각각에는 후행이 있습니다 s///. 이는 각 교체가 각 패턴의 두 번째 발생에 대한 것이기 때문입니다. 두 번째 발생이 존재하지 않으면 교체가 이루어지지 않습니다. 위는 내 다른 스크립트에서 실행한 결과입니다. sed특수 문자나 유사한 문자의 영향을 받지 않는 것 같습니다.

글을 쓰면서 선택 항목에 색상을 지정하면 무슨 일이 일어나고 있는지 더 쉽게 알 수 있습니다.

s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g

...그 라인은 그렇습니다. 댓글을 달거나 삭제할 수 있습니다(이전에 사용했지만 원하지 않거나 필요하지 않음).

예제 데이터에 대해 작성하는 스크립트는 다음과 같습니다.

1{
    s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(xyz\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(aa\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
 }

인쇄되는 내용은 다음과 같습니다.

qq    ab xyz     +ab+ +qq+ aa +ab+

sed그리고 내 이전 스크립트 중 일부는 다음과 같습니다.

        s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${+esc+}0m/g
        s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${+esc+}0m/g
        s/.${bs}//g
        s/\(\(${esc}\)0m\2[^m]*+m+[_ ]\{,+2+\}\)\{+2+\}/_/g
n;      /./!N;G

관련 정보