문자열 인스턴스의 범위를 변경하는 방법

문자열 인스턴스의 범위를 변경하는 방법

텍스트 파일의 각 줄에 있는 하위 문자열의 일부 인스턴스를 변경해야 합니다. 이러한 인스턴스는 모두 연속적입니다(예: 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:

세 번째에서 여섯 번째 as를 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/3gfoo

따라서 다음과 같은 고정 문자열의 경우 다음을 수행합니다.

$ echo aaaaaaaaa | sed 's/a/\n/3g;s/\n/a/5g;s/\n/b/g'
aabbbbaaa

즉, 마지막 개행 문자a 에서 세 번째 문자를 개행 문자로 대체하고(패턴 공간에서 다른 상황이 발생하지 않도록 보장), 마지막 개행 문자 에서 다섯 번째 문자를 다시 s(6 - 3 + 1 = 4)로 복원합니다. 원하는 as)의 수로 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를 as로 변경하려면 다음을 수행하십시오.wall

$ echo aaallaaallaaa | perl -pe 's{all.*?all}{$& =~ s/a/w/gr}e'
aawllwwwllaaa

\ball분리가 필요한 경우 단어 경계 연산자를 사용하세요.성격.

$ 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=localeASCII로만 가정하기보다는 로케일 문자 맵에 따라 디코딩할 문자를 추가하십시오. 예를 들어 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'
  • 그러면 첫 번째와 마지막 항목이 대체될 변수 frstsum 으로 전달됩니다 .lstawk
  • 그런 다음 라인에서 검색 패턴의 -번째 발생을 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=aawk에게 문자를 기준으로 레코드를 분할하도록 지시하고 a다른 awk 변수도 다음과 같이 정의합니다.시작,그리고바꾸다는 각각 대상 문자 "a"의 시작 위치와 끝 위치이며, 이를 "w" 문자로 대체합니다.

그런 다음 필드를 반복하고 필드 자체를 인쇄합니다. 필드 번호가 시작점과 끝점 사이에 있으면 필드 자체를 인쇄하고, 그렇지 않은 경우 문자 "a"를 인쇄합니다. 마지막으로 마지막 필드도 출력합니다.

코드 조각 실행

답변4

사용행복하다(이전 Perl_6)

~$ echo aaaaaaaa | perl6 -pe 's:nth(3..6)/a/b/;'
aabbbbaa

Raku(Perl 계열의 프로그래밍 언어)에는 , 등 의 동의어를 nth지원하는 새로운 정규식 수정자("위치 부사") 가 있습니다. 일반적인 대체 목적으로 숫자 또는 범위 인수를 삽입하십시오.1st2nd3rdnth()

위의 버전은 빠른 버전입니다. 다음은 이와 관련하여 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

관련 정보