텍스트 파일의 각 줄에 있는 하위 문자열의 일부 인스턴스를 변경해야 합니다. 이러한 인스턴스는 모두 연속적입니다(예: 3~6 또는 2~5 등). 이 작업에는 어떤 명령이 필요합니까? 내가 얻은 가장 가까운 것은 다음과 같습니다.
sed 's/this/that/3' file1
이것은 세 번째에만 상황을 바꿉니다. 같은 게 있었으면 좋겠다
sed 's/this/that/3,6' file1
대답일 수도 있지만 sed
범위가 나타나지 않습니다.
입력 예:
I want to change all letters "a" to "w" starting from the word "all" until the second "all" (inclusive)
예상 출력:
I want to change wll letters "w" to "w" stwrting from the word "wll" until the second "all" (inclusive)
답변1
그리고 perl
:
세 번째에서 여섯 번째 a
s를 s로 변경합니다 b
.
$ echo aaaaaaaaa | perl -pe '$n=0; s{a}{++$n;$n==3..$n==6?"b":$&}ge'
aabbbbaaa
이는 연산자 e
의 플래그를 사용하므로 s{regex}{replacement}flags
대체는 코드로 평가되며, "b"
이는 증가된 카운터가 3과 6 사이이면 제공되고, $&
그렇지 않으면 일치하는 값( )이 제공됩니다. 또는:
$ echo aaaaaaaa | perl -pe '$n=0; s/a(?(?{++$n; $n == 3 .. $n == 6})|(*FAIL))/b/g'
aabbbbaa
증가하는 카운터가 3 .. 6 범위에 없는 경우 정보를 (?(condition)yes|no)
제공하는 정규식 연산자를 사용하십시오 .(*FAIL)
GNU는 세 번째 및 후속 항목 교체를 sed
지원합니다 .s/foo/bar/3g
foo
따라서 다음과 같은 고정 문자열의 경우 다음을 수행합니다.
$ echo aaaaaaaaa | sed 's/a/\n/3g;s/\n/a/5g;s/\n/b/g'
aabbbbaaa
즉, 마지막 개행 문자a
에서 세 번째 문자를 개행 문자로 대체하고(패턴 공간에서 다른 상황이 발생하지 않도록 보장), 마지막 개행 문자 에서 다섯 번째 문자를 다시 s(6 - 3 + 1 = 4)로 복원합니다. 원하는 a
s)의 수로 a
따라서 다음 항목을 복원한 다음 b
나머지 줄 바꿈을 모두 s로 바꾸십시오.
무엇이든 sed
:
sed 's/a/\
/g
s/\n/b/3
s/\n/b/3
s/\n/b/3
s/\n/b/3
s/\n/a/g'
처음 두 발생 사이의 s를 a
s로 변경하려면 다음을 수행하십시오.w
all
$ echo aaallaaallaaa | perl -pe 's{all.*?all}{$& =~ s/a/w/gr}e'
aawllwwwllaaa
\b
all
분리가 필요한 경우 단어 경계 연산자를 사용하세요.성격.
$ echo 'alloy (all-hands aaa ball all) fall' | perl -pe 's{all.*?all}{$& =~ s/a/w/gr}e'
wlloy (wll-hands aaa ball all) fall
$ echo 'alloy (all-hands aaa ball all) fall' | perl -pe 's{\ball\b.*?\ball\b}{$& =~ s/a/w/gr}e'
alloy (wll-hwnds www bwll wll) fall
( -Mopen=locale
ASCII로만 가정하기보다는 로케일 문자 맵에 따라 디코딩할 문자를 추가하십시오. 예를 들어 allée
프랑스어 단어를 UTF-8로 인코딩하고 all
뒤에 단어가 아닌 문자가 나오지 않습니다.)
답변2
에서는 이것이 불가능할 수도 있지만 sed
다음 GNU awk
프로그램은 작동합니다:
awk -v frst=2 -v lst=5 '{for (i=1; i<=(lst-frst+1);i++) $0=gensub(/a/,"w",frst)}1'
- 그러면 첫 번째와 마지막 항목이 대체될 변수
frst
sum 으로 전달됩니다 .lst
awk
- 그런 다음 라인에서 검색 패턴의 -번째 발생을
gensub()
대체 하고 결과를 현재 라인 버퍼에 다시 할당하는 데 사용됩니다 .frst
lst-frst+1
필요한 모든 이벤트를 대체하기 위해 총 ( ) 번 실행됩니다 . 그런 다음 현재 줄을 인쇄합니다(모든 수정 사항 포함).- 대체된 항목은 더 이상 다음 루프 반복에 포함되지 않으므로 대체될 문자열의 항목 수는 항상 동일하게 유지됩니다.
적용 예:
$ echo "a1a2a3a4a5a6" | awk -v frst=2 -v lst=5 '{for (i=1; i<=(lst-frst+1);i++) $0=gensub(/a/,"w",frst)}1'
a1w2w3w4w5a6
또는 원본:
$ echo 'I want to change all letters "a" to "w" starting from the word "all" until the second "all" (inclusive)' | awk -v frst=3 -v lst=6 '{for (i=1; i<=(lst-frst+1);i++) $0=gensub(/a/,"w",frst)}1'
I want to change wll letters "w" to "w" stwrting from the word "wll" until the second "all" (inclusive)
항상 그렇듯이 검색 패턴이 겹칠 수 있으면 예상대로 작동하지 않습니다.
답변3
어떤 이상한 경우 :
awk -v FS='a' -v start=3 -v end=6 -v replace="w" '
{
for(i=1; i<NF; i++)
printf("%s", $i (start<=i && i<=end? replace: FS))
print $NF
}' infile
여기서는 FS=a
awk에게 문자를 기준으로 레코드를 분할하도록 지시하고 a
다른 awk 변수도 다음과 같이 정의합니다.시작,끝그리고바꾸다는 각각 대상 문자 "a"의 시작 위치와 끝 위치이며, 이를 "w" 문자로 대체합니다.
그런 다음 필드를 반복하고 필드 자체를 인쇄합니다. 필드 번호가 시작점과 끝점 사이에 있으면 필드 자체를 인쇄하고, 그렇지 않은 경우 문자 "a"를 인쇄합니다. 마지막으로 마지막 필드도 출력합니다.
답변4
사용행복하다(이전 Perl_6)
~$ echo aaaaaaaa | perl6 -pe 's:nth(3..6)/a/b/;'
aabbbbaa
Raku(Perl 계열의 프로그래밍 언어)에는 , 등 의 동의어를 nth
지원하는 새로운 정규식 수정자("위치 부사") 가 있습니다. 일반적인 대체 목적으로 숫자 또는 범위 인수를 삽입하십시오.1st
2nd
3rd
nth()
위의 버전은 빠른 버전입니다. 다음은 이와 관련하여 Raku의 정규식 수정자가 얼마나 직관적인지 보여주기 위한 것입니다( 테마 변수를 다시 로드하는 데 사용될 때마다 6th
, 5th
, 4th
의 일치 항목 3rd
이 연속적으로 대체됩니다 ).andthen
$_
~$ echo aaaaaaaa | perl6 -ne 'S:6th/a/b/ andthen S:5th/a/b/ andthen S:4th/a/b/ andthen S:3rd/a/b/ andthen .put;'
aabbbbaa
https://docs.raku.org/언어/regexes#Positional_adverbs
https://raku.org