비슷한 작업을 수행하려면 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
또 다른 접근 방식은 다음과 같습니다. 이는 일부 sed
s를 사용합니다.
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