sed를 사용한 대소 문자 일치 패턴 교체


14

여러 파일에 소스 코드가 분산되어 있습니다.

  • abcdef교체해야 할 패턴 이 pqrstuvxyz있습니다.
  • 패턴은 Abcdef(문장) 일 수 있으며로 교체해야합니다 Pqrstuvxyz.
  • 패턴은 AbCdEf(케이스 전환) 일 수 있으며로 교체해야합니다 PqRsTuVxYz.

즉, 소스 패턴의 대소 문자를 일치시키고 적절한 대상 패턴을 적용해야합니다.

sed도구 나 다른 도구를 사용하여 어떻게이 작업을 수행 할 수 있습니까?


그리고 만약 그렇다면 ABcDeF?
Stéphane Chazelas

PQrStUvxyz-요점을 알았습니다.
user1263746

따라서 ABcDeF-> PQrStUvxyz이면 반드시 AbCdEf-> PqRsTuvxyz는 논리적으로 일관됩니다. 사례를 한 문자열에서 다른 문자열로 복사하려는 경우 두 번째 교체 문자열이 더 길면 어떻게됩니까?
Graeme

간결성을 위해 대체물을 "pqrstu"로 다듬을 수 있습니다.
user1263746

답변:


9

다음을 사용하는 휴대용 솔루션 sed:

sed '
:1
/[aA][bB][cC][dD][eE][fF]/!b
s//\
&\
pqrstu\
PQRSTU\
/;:2
s/\n[[:lower:]]\(.*\n\)\(.\)\(.*\n\).\(.*\n\)/\2\
\1\3\4/;s/\n[^[:lower:]]\(.*\n\).\(.*\n\)\(.\)\(.*\n\)/\3\
\1\2\4/;t2
s/\n.*\n//;b1'

GNU sed를 사용하면 조금 더 쉽습니다.

search=abcdef replace=pqrstuvwx
sed -r ":1;/$search/I!b;s//\n&&&\n$replace\n/;:2
    s/\n[[:lower:]](.*\n)(.)(.*\n)/\l\2\n\1\3/
    s/\n[^[:lower:]](.*\n)(.)(.*\n)/\u\2\n\1\3/;t2
    s/\n.*\n(.*)\n/\1/g;b1"

&&&위의 방법 을 사용 하여 나머지 교체에 문자열의 대소 문자 패턴을 재사용하므로 및 로 ABcdef변경 됩니다 . 처음 6 자의 경우에만 영향을 주도록 변경하십시오 .PQrstuVWxAbCdEfPqRsTuVwX&

(주 당신이 원하는 일을하지 않을 수 또는 대체하는 경우 대체 예를 들어 대체 (대상이 될 수 있습니다 경우 무한 루프로 실행할 수 있습니다 foo에 대한 foo, 또는 bcd에 대한 abcd)


8

다음을 사용하는 휴대용 솔루션 awk:

awk -v find=abcdef -v rep=pqrstu '{
  lwr=tolower($0)
  offset=index(lwr, tolower(find))

  if( offset > 0 ) {
    printf "%s", substr($0, 0, offset)
    len=length(find)

    for( i=0; i<len; i++ ) {
      out=substr(rep, i+1, 1)

      if( substr($0, offset+i, 1) == substr(lwr, offset+i, 1) )
        printf "%s", tolower(out)
      else
        printf "%s", toupper(out)
    }

    printf "%s\n", substr($0, offset+len)
  }
}'

입력 예 :

other abcdef other
other Abcdef other
other AbCdEf other

출력 예 :

other pqrstu other
other Pqrstu other
other PqRsTu other

최신 정보

주석에서 지적했듯이 위의 내용 find은 모든 줄 의 첫 번째 인스턴스 만 대체합니다 . 모든 인스턴스를 바꾸려면

awk -v find=abcdef -v rep=pqrstu '{
  input=$0
  lwr=tolower(input)
  offset=index(lwr, tolower(find))

  if( offset > 0 ) {
    while( offset > 0 ) {

      printf "%s", substr(input, 0, offset)
      len=length(find)

      for( i=0; i<len; i++ ) {
        out=substr(rep, i+1, 1)

        if( substr(input, offset+i, 1) == substr(lwr, offset+i, 1) )
          printf "%s", tolower(out)
        else
          printf "%s", toupper(out)
      }

      input=substr(input, offset+len)
      lwr=substr(lwr, offset+len)
      offset=index(lwr, tolower(find))
    }

    print input
  }
}'

입력 예 :

other abcdef other ABCdef other
other Abcdef other abcDEF
other AbCdEf other aBCdEf other

출력 예 :

other pqrstu other PQRstu other
other Pqrstu other pqrSTU
other PqRsTu other pQRsTu other

한 줄에 하나의 인스턴스 만 처리합니다.
Stéphane Chazelas

@StephaneChazelas, 여러 인스턴스를 처리하도록 업데이트되었습니다.
Graeme

6

사용할 수 있습니다 perl. 자주 묻는 질문에서 인용 perldoc perlfaq6:

RHS에서 케이스를 보존하면서 LHS에서 대소 문자를 구분하지 않고 대체하는 방법은 무엇입니까?

Larry Rosler의 멋진 Perlish 솔루션입니다. ASCII 문자열에서 비트 xor의 속성을 이용합니다.

   $_= "this is a TEsT case";

   $old = 'test';
   $new = 'success';

   s{(\Q$old\E)}
   { uc $new | (uc $1 ^ $1) .
           (uc(substr $1, -1) ^ substr $1, -1) x
           (length($new) - length $1)
   }egi;

   print;

그리고 여기에 위의 모델을 모델로 한 서브 루틴이 있습니다 :

       sub preserve_case($$) {
               my ($old, $new) = @_;
               my $mask = uc $old ^ $old;

               uc $new | $mask .
                       substr($mask, -1) x (length($new) - length($old))
   }

       $string = "this is a TEsT case";
       $string =~ s/(test)/preserve_case($1, "success")/egi;
       print "$string\n";

인쇄합니다 :

           this is a SUcCESS case

대안으로, 원래 단어보다 긴 대체 단어의 경우를 유지하기 위해 Jeff Pinyan의이 코드를 사용할 수 있습니다.

   sub preserve_case {
           my ($from, $to) = @_;
           my ($lf, $lt) = map length, @_;

           if ($lt < $lf) { $from = substr $from, 0, $lt }
           else { $from .= substr $to, $lf }

           return uc $to | ($from ^ uc $from);
           }

문장이 "이것은 성공 사례입니다"로 변경됩니다.

C 프로그래머가 모든 프로그래밍 언어로 C를 작성할 수 있음을 보여주기 위해 C와 같은 솔루션을 선호하는 경우 다음 스크립트는 대체 문자를 대소 문자와 동일하게 만듭니다. (또한 Perlish 솔루션이 실행하는 것보다 약 240 % 느리게 실행됩니다.) 대체에 대체되는 문자열보다 많은 문자가있는 경우 마지막 대체 문자는 마지막 대체 문자에 사용됩니다.

   # Original by Nathan Torkington, massaged by Jeffrey Friedl
   #
   sub preserve_case($$)
   {
           my ($old, $new) = @_;
           my ($state) = 0; # 0 = no change; 1 = lc; 2 = uc
           my ($i, $oldlen, $newlen, $c) = (0, length($old), length($new));
           my ($len) = $oldlen < $newlen ? $oldlen : $newlen;

           for ($i = 0; $i < $len; $i++) {
                   if ($c = substr($old, $i, 1), $c =~ /[\W\d_]/) {
                           $state = 0;
                   } elsif (lc $c eq $c) {
                           substr($new, $i, 1) = lc(substr($new, $i, 1));
                           $state = 1;
                   } else {
                           substr($new, $i, 1) = uc(substr($new, $i, 1));
                           $state = 2;
                   }
           }
           # finish up with any remaining new (for when new is longer than old)
           if ($newlen > $oldlen) {
                   if ($state == 1) {
                           substr($new, $oldlen) = lc(substr($new, $oldlen));
                   } elsif ($state == 2) {
                           substr($new, $oldlen) = uc(substr($new, $oldlen));
                   }
           }
           return $new;
   }

ASCII 문자로 제한됩니다.
Stéphane Chazelas

5

replace를로 다듬 으면 다음을 pqrstu시도하십시오.

입력:

abcdef
Abcdef
AbCdEf
ABcDeF

출력 :

$ perl -lpe 's/$_/$_^lc($_)^"pqrstu"/ei' file
pqrstu
Pqrstu
PqRsTu
PQrStU

로 바꾸려면 다음과 prstuvxyz같이하십시오.

$ perl -lne '@c=unpack("(A4)*",$_);
    $_ =~ s/$_/$_^lc($_)^"pqrstu"/ei;
    $c[0] =~ s/$c[0]/$c[0]^lc($c[0])^"vxyz"/ei;
    print $_,$c[0]' file
pqrstuvxyz
PqrstuVxyz
PqRsTuVxYz
PQrStUVXyZ

map- ABcDeF>에 대한 규칙을 찾을 수 없습니다 PQrStUvxyz.


ASCII 문자로 제한됩니다.
Stéphane Chazelas

3

이것과 같은 것이 당신이 묘사 한 것을 할 것입니다.

sed -i.bak -e "s/abcdef/pqrstuvxyz/g" \
 -e "s/AbCdEf/PqRsTuVxYz/g" \
 -e "s/Abcdef/Pqrstuvxyz/g" files/src
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.