여러 파일에 소스 코드가 분산되어 있습니다.
abcdef
로 바꿔야 할 패턴이 있습니다pqrstuvxyz
.- 패턴은
Abcdef
(Sentence Case)일 수 있으며, 다음으로 바꿔야 합니다Pqrstuvxyz
. - 패턴은
AbCdEf
(Toggle Case) 일 수 있으며PqRsTuVxYz
.
즉, 소스 패턴의 대소문자를 일치시키고 그에 맞는 타겟 패턴을 적용해야 합니다.
sed
이를 달성하기 위해 어떻게 다른 도구를 사용할 수 있습니까 ?
답변1
휴대용 솔루션의 용도 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
변경 됩니다 PQrstuVWx
. 처음 6자의 대소문자에만 영향을 미치도록 변경하세요.AbCdEf
PqRsTuVwX
&
(대체가 필요한 경우(예: foo
for foo
또는 bcd
for 교체 abcd
) 원하는 대로 작동하지 않거나 무한 루프에 빠질 수 있습니다.
답변2
휴대용 솔루션의 용도 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
답변3
perl
다음에서 인용된 FAQ에서 직접 사용할 수 있습니다 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);
}
그러면 문장이 "This is auccess story"로 변경됩니다.
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;
}
답변4
이와 같은 것이 당신이 설명하는 것을 할 것입니다.
sed -i.bak -e "s/abcdef/pqrstuvxyz/g" \
-e "s/AbCdEf/PqRsTuVxYz/g" \
-e "s/Abcdef/Pqrstuvxyz/g" files/src