Sed에서 캡처 그룹 반복

Sed에서 캡처 그룹 반복

다음과 같은 스키마가 있습니다.

#ABC: (0),(0-11,22),(A7E2BB0F38DF),(42),(1A0290800D7),(7042),(81A0290800D7),(7442)

sed를 사용하여 다음 결과를 얻고 싶습니다.

0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

다음은 bash에서 작동합니다:

result="#ABC: (0),(0-11,22),(A7E2BB0F38DF),(42),(1A0290800D7),(7042),(81A0290800D7),(7442)"
sed -n 's/.*(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\))/\1 \2 \3 \4 \5 \6 \7 \8/p' <<< "$result"
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

이제 이 sed 표현식을 어떻게 최적화합니까? 중복 캡처 그룹을 제거하는 방법은 무엇입니까?

답변1

괜찮나요?

% sed -Ee 's/[^(]*\(([^)]*)\)/\1 /g' < input.txt
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442 

즉, 첫 번째 여는 괄호( ) [^(]*\(앞의 모든 항목 과 일치하고 ([^)]*)닫는 괄호( )가 아닌 모든 항목을 캡처한 다음 닫는 괄호와 일치하고 일괄 처리를 캡처된 부분( )으로 바꾸고 \1나머지 문자열( /g) .

또는 Perl에서는:

% perl -ne 'print "$1 " while(/\((.*?)\)/g); print "\n"' < input.txt
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442 

답변2

질문에 표시된 원래 입력이 일부 구조화된 문서 형식(예: YAML 또는 JSON)의 더 큰 문서 조각이 아니라고 가정합니다. 그렇다면 여기 또는 다른 답변에 제시된 것보다 이를 달성하는 더 좋은 방법이 있을 수 있습니다.


이렇게 하면 지정한 것과 반대되는 방식으로 원하는 작업이 달성됩니다. 대괄호 안의 내용을 일치시키고 유지하는 대신 첫 번째 항목 (과 그 앞의 모든 항목, 마지막 항목 )과 그 뒤의 모든 항목을 제거한 다음 ),(하위 문자열의 각 인스턴스를 공백으로 바꿉니다.

$ sed -e 's/[^(]*(//' -e 's/)[^)]*$//' -e 's/),(/ /g' file
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

또는 공백을 먼저 사용하여 ),(대괄호와 괄호를 너무 많이 사용하지 않고 다른 대체 항목을 다시 작성할 수 있습니다(입력의 외부 괄호에 괄호로 묶인 하위 문자열이 포함되어 있지 않다고 가정).

$ sed -e 's/),(/ /g' -e 's/.*(//' -e 's/).*//' file
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

남은 것은 대괄호 밖에 있지 않은 부분 문자열입니다(공백으로 구분됨).


완전히 다른 접근 방식은 첫 번째 이전 텍스트를 제거한 (다음 (각 합계를 큰따옴표로 변환하여 )입력을 적절하게 인용된 CSV로 변환하는 것 입니다. 그러면 우리는 csvformat다음에서 사용할 수 있습니다csvkit기본 필드 구분 기호를 공백으로 변경합니다.

$ sed -e 's/[^(]*(/(/' -e 'y/()/""/' file | csvformat -D ' '
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

관련 정보