문자열 패턴의 가장 짧은 일치 항목 바꾸기

문자열 패턴의 가장 짧은 일치 항목 바꾸기

나는 이 문자열을 가지고 있습니다 :

update mytable set mycol=myvalue where mycol=yourvalue;

다음으로 변환해야 합니다.

insert into mytemp select * from mytable where mycol=youvalue;

나는 이렇게 할 수 있고 훌륭하게 작동합니다.

sed -e 's/^Update.*where//ig' -e "s/^/insert into mytemp select * from mytable where  /g" n.txt

하지만:

문자열이 다음과 같은 경우:

update mytable set mycol=myvalue where mycol=(select yourcol from yourtable where youcol=yourvalue);

나는 얻다:

insert into mytemp select * from mytable where youcol=yourvalue);

그리고 나는 원한다:

insert into mytemp select * from mytable where mycol=(select yourcol from yourtable where youcol=yourvalue);

어떡해?

답변1

기본적으로 sed정규식 엔진은 탐욕적입니다. 이는 패턴이 항상 가능한 가장 긴 일치 항목과 일치함을 의미합니다. 탐욕스럽지 않은 검색을 해야 하는데 sed가 탐욕스럽지 않은 검색을 지원하지 않는 것 같습니다. 따라서 sed가능한 가장 짧은 일치 항목을 찾을 수 있도록 검색 패턴에 피벗 포인트를 추가해야 합니다 .

다음 줄은 탐욕스럽지 않은 특수한 일치를 시뮬레이션하려고 시도하며, w첫 번째와 첫 번째 사이의 단일이 패턴을 무효화하므로 일반성이 필요하지 않습니다.updatewhere

sed -e 's/^Update[^w]*where//ig'\
    -e "s/^/insert into mytemp select * from mytable where  /g" n.txt

perl및 중 하나 와 같은 다른 정규식 엔진은 이 기능을 지원합니다 awk.

하지만 당신의 경우에는 다음과 같은 표현이 필요하다고 생각합니다.

sed -e 's/^Update.\+where\(.\+where.*\)$/\
insert into mytemp select * from mytable where \1/ig'  n.txt

귀하의 특정 질문에 더 편리할 것입니다.

(위 라인의 예고편은 \라인을 더 명확하게 하기 위해 추가되었습니다.)

답변2

정규식 일치는 왼쪽에서 오른쪽으로 진행되며 가장 긴 일치 항목에 우선순위를 부여합니다. 따라서 해당 줄 ^Update.*where의 마지막 항목 과 일치합니다.where

이 일치를 수행하는 한 가지 방법은 non-greedy 수량자를 사용하는 것입니다 *. Sed는 non-greedy 수량자를 지원하지 않지만 Perl은 지원합니다.

perl -pe 's/^update.*?where//i; s/^/insert into mytemp select .*? from mytable where /'

데이터와 일치할 수도 있고 일치하지 않을 수도 있는 또 다른 접근 방식은 테이블 이름과 열 설정에서 괄호를 거부하는 것입니다.

sed -e 's/^update[^()]*where//i' -e 's/^/insert into mytemp select [^()]* from mytable where /'

보다 정교한 접근 방식은 먼저 where첫 번째 토큰을 고유한 토큰으로 바꾼 다음 대체를 수행하고 마지막으로 토큰을 로 복원하는 것입니다 where. sed는 한 줄씩 실행되므로 \n다음과 같이 줄에 개행 문자가 포함되지 않는 것이 보장됩니다. sed.

sed -e 's/ where /\n/' \
    -e 's/^update.*$//i' -e 's/^/insert into mytemp select .* from mytable where /' \
    -e 's/\n/ where/'

관련 정보