AWK에서 정규 표현식의 탐욕을 줄이는 방법은 무엇입니까?

AWK에서 정규 표현식의 탐욕을 줄이는 방법은 무엇입니까?

나는 이것을 알아 내려고 노력하고 있습니다 awk. 예는 다음과 같습니다.

echo "@article{gjn, Author =   {Grzegorz J. Nalepa}, " | awk '{ sub(/@.*,/,""); print }'

더 짧은 문자열을 선택하는 정규식을 작성할 수 있습니까?

@article{gjn,

이 긴 문자열 대신? :

@article{gjn, Author =   {Grzegorz J. Nalepa},

나는 이 결과를 얻고 싶습니다:

 Author =   {Grzegorz J. Nalepa},



또 다른 예가 있습니다.

에코",기사 {gjn, 저자 = {Grzegorz J. Nalepa}, " | awk '{ sub(/,[^,]*,/,"");인쇄}'
      ↑ ^^^^^^

입력 문자열과 정규 표현식의 첫 번째 위치에 있는 문자를 @쉼표( ) 문자로 변경했습니다. 더 짧은 문자열을 선택하는 정규식을 작성할 수 있습니까?,.*[^,]*

, Author =   {Grzegorz J. Nalepa},

긴 문자열 대신? :

,article{gjn, Author =   {Grzegorz J. Nalepa},

나는 이 결과를 얻고 싶습니다:

,article{gjn

답변1

이 이후의 @첫 번째 항목을 선택하려면 ,다음과 같이 지정해야 합니다.@[^,]*,

그 뒤에는 쉼표가 아닌 @숫자 ( )가 오고 그 뒤에 쉼표( )가 옵니다.*[^,],

이 방법은 동일하게 작동 하지만 뒤에 나오는 내용이 하나 이상의 문자이기 때문에 @.*?,유사한 작업에는 작동하지 않습니다 . @.*?string캐릭터를 부정하기는 쉽지만,정규식에서 문자열을 부정하는 것은 훨씬 더 어렵습니다..

또 다른 접근 방식은 입력을 전처리하여 string입력에 나타나지 않는 문자로 바꾸거나 앞에 추가하는 것입니다.

gsub(/string/, "\1&") # pre-process
gsub(/@[^\1]*\1string/, "")
gsub(/\1/, "") # revert the pre-processing

입력에 대체 문자( \1위)가 포함되어 있지 않다고 보장할 수 없는 경우 한 가지 접근 방식은 이스케이프 메커니즘을 사용하는 것입니다.

gsub(/\1/, "\1\3") # use \1 as the escape character and escape itself as \1\3
                   # in case it's present in the input
gsub(/\2/, "\1\4") # use \2 as our maker character and escape it
                   # as \1\4 in case it's present in the input
gsub(/string/, "\2&") # mark the "string" occurrences

gsub(/@[^\2]*\2string/, "")

# then roll back the marking and escaping
gsub(/\2/, "")
gsub(/\1\4/, "\2")
gsub(/\1\3/, "\1")

이는 고정 s에서는 작동 하지만 임의 의 string정규식에서는 작동하지 않습니다.@.*?foo.bar

답변2

해결 방법을 제공하는 몇 가지 좋은 답변이 이미 있습니다. awk탐욕스럽지 않은 일치를 수행할 수 없는 것에 대한 몇 가지 좋은 답변이 이미 있습니다.Perl 호환 정규식(PCRE). 대부분의 간단한 "일치 및 인쇄" 스크립트는 awk쉽게 perl사용할 수 -n있으며 더 복잡한 스크립트는 다음을 사용하여 변환할 수 있습니다.a2pPerl 번역가에게는 어이가 없습니다.

진주Perl 스크립트와 PCRE를 사용하는 모든 것에서 사용할 수 있는 탐욕스럽지 않은 연산자가 있습니다. 예를 들어 GNU grep 옵션에서도 구현됩니다 -P.

PCRE는동일하지 않음Perl의 정규식과 유사하지만 매우 유사합니다. 이는 속도가 매우 빠르고 Perl의 확장 정규식 향상 기능이 매우 유용하기 때문에 많은 프로그램의 정규식 라이브러리로 널리 선택됩니다.

~에서페레(1)매뉴얼 페이지:

   By default, a quantified subpattern is "greedy", that is, it will match
   as many times as possible (given a particular starting location) while
   still allowing the rest of the pattern to match.  If you want it to
   match the minimum number of times possible, follow the quantifier with
   a "?".  Note that the meanings don't change, just the "greediness":

       *?        Match 0 or more times, not greedily
       +?        Match 1 or more times, not greedily
       ??        Match 0 or 1 time, not greedily
       {n}?      Match exactly n times, not greedily (redundant)
       {n,}?     Match at least n times, not greedily
       {n,m}?    Match at least n but not more than m times, not greedily

답변3

이것은 오래된 기사이지만 다음 정보는 다른 사람들에게 유용할 수 있습니다.

awk에서 탐욕스럽지 않은 RE 매칭을 수행하는 방법이 있습니다. 기본 아이디어는 match(string, RE) 함수를 사용하고 일치가 실패할 때까지 (테스트되지 않음) 다음과 같이 문자열 크기를 점차적으로 줄이는 것입니다.

if (match(string, RE)) {
    rstart = RSTART
    for (i=RLENGTH; i>=1; i--)
        if (!(match(substr(string,1,rstart+i-1), RE))) break;
    # At this point, the non-greedy match will start at rstart
    #  for a length of i+1
}

답변4

awk에서는 탐욕스럽지 않은 일치를 수행할 수 있는 방법이 없습니다. 그러나 원하는 결과를 얻을 수도 있습니다. sch의 제안이 해당 라인에 적용됩니다. 쉼표에 의존할 수 없지만 "작성자"가 항상 원하는 내용의 시작 부분인 경우 다음과 같이 할 수 있습니다.

awk '{ sub(/@.*Author/,"Author"); print }'

Author 앞의 문자 수가 항상 동일한 경우 다음을 수행할 수 있습니다.

awk '{ sub(/@.{21}/,""); print }'

전체 데이터 세트에서 데이터가 어떻게 보이는지 알아야 합니다.

관련 정보