2013-02-19 5 views
3

텍스트 파일에서 문자열을 검색하고 매치마다 증가하는 숫자가 포함 된 대체물을 만들어야합니다.awk (gawk)와 관련된 문제

"찾을"문자열은 단일 문자 또는 단어 또는 구일 수 있습니다.

대체 표현식이 항상 같지는 않지만 (아래 예제에서와 같이) 항상 증가하는 숫자 (변수)가 포함됩니다. 예를 들어

:

1) 나는 "data.txt로"라는 이름의 테스트 파일이 있습니다. 파일에 다음이 포함되어 있습니다.

2) awk 스크립트를 "cmd.awk"라는 파일에 저장했습니다. 이 파일에는 다음이 포함

Now is the time 
f(1)or all good men 
to come to the 
aid of(2) their party. 

문제는 더있다 올 때 :이 경우

awk -f cmd.awk data.txt 

는, 출력이 예상과 같이

/f/ {sub ("f","f(" ++j ")")}1 

3) 나는이 같은 AWK 사용 한 줄에 한 경기 이상 예를 들어, 내가 문자를 검색 할 경우 "I"와 같은 :

/i/ {sub ("i","i(" ++j ")")}1 

출력은 다음과 같습니다 잘못

Now i(1)s the time 
for all good men 
to come to the 
ai(2)d of their party. 

이가 "I" "시간"에 포함되어 있지 않기 때문에 또는 "그들의".

그래서, 내가 좋아하는 대신 "하위"의 "GSUB"시도 :

/i/ {gsub ("i","i(" ++j ")")}1 

을 출력은 다음과 같습니다

Now i(1)s the ti(1)me 
for all good men 
to come to the 
ai(2)d of thei(2)r party. 

지금은 편지의 모든 발생을 교체하게 "I" 삽입 된 숫자는 같은 줄에있는 모든 일치 항목에 대해 동일합니다.

원하는 출력은 다음과 같아야합니다

Now i(1)s the ti(2)me 
for all good men 
to come to the 
ai(3)d of thei(4)r party. 

참고 :

awk -f cmd.awk -v j=26 data.txt 

출력을 얻으려면 : 수는 항상이 같은 AWK를 사용할 수 있습니다 "1"로 시작하지 않을 것이다 :

Now i(27)s the ti(28)me 
for all good men 
to come to the 
ai(29)d of thei(30)r party. 

그리고 분명히 알 수 있듯이 대체 할 숫자가 항상 괄호 안에있는 것은 아닙니다. 대체 문자열에는 항상 일치하는 문자열이 포함되지는 않습니다 (실제로는 매우 드뭅니다).

에 대한 I이가 함께 데 다른 문제 ...

내가 AWK 변수 (환경하지 변수)를 사용하고자하는 "문자열 검색", 그래서 나는 awk 명령 줄에서 지정할 수 있습니다 .예를 들어

는 :

1) 나는 "cmd.awk"라는 이름의 파일에 awk 스크립트를 배치했다.

/??a??/ {gsub (a,a "(" ++j ")")}1 

2)는 다음과 같이 AWK를 사용합니다 :

awk -f cmd.awk -v a=i data.txt 

출력을 얻으려면 : 파일 같은 것을 포함

Now i(1)s the ti(2)me 
for all good men 
to come to the 
ai(3)d of thei(4)r party. 

여기서 문제는, 내가 표현 어떻게입니다/검색/표현식의 변수 "a"?

답변

2

AWK 버전 :

awk '{for(i=2; i<=NF; i++)$i="(" ++k ")" $i}1' FS=i OFS=i 
+0

Windows 명령 줄에서 작동하게하려면 따옴표를 사용해야했습니다. awook BEGIN {FS = \ "i \"; OFS = \ "i \"; k = 0} {for (i = 2; i <= NF; i ++) $ i = \ "(\"++ k \ ") \"$ i} 1 ""data.txt ". 변수 "i"의 일부 사용이 "$"("$ i")로 시작되는 이유를 설명 할 수 있습니까? –

+0

변수는 $ -sign을 사용하지 않지만 필드 ($ 1, $ 2, ..)는 레코드 자체 ($ 0)를 수행합니다. 그러나 i = 5 일 경우 $ i는 $ 5를 의미합니다. – Scrutinizer

+0

@KevinFegan은 Windows의 명령 줄에서 awk 스크립트를 사용하지 마십시오. 찾은대로 인용 및 다른 문제가 발생합니다. 대신 스크립트를 "foo.awk"라는 파일에 넣고 awk -f foo.awk data.txt로 실행하십시오. 스크립팅을위한 Windows라는 악몽을 피하기 위해 cygwin을 설치하는 방법을 살펴볼 수 있습니다. –

1

awk을 사용하여이 작업을 수행 할 수 없다는 것은 아니지만보다 강력한 언어로 옮길 것을 강력히 권장합니다. 대신 perl을 사용하십시오.

(26)에서 시작하는 편지 i의 수를 포함하려면 시도 :

var=26 
perl -spe 's:i:$&."(".++$x.")":ge' -- -x=$var data.txt 

결과 :

Now i(27)s the ti(28)me 
for all good men 
to come to the 
ai(29)d of thei(30)r party. 

perl -spe 's:i:$&."(".++$x.")":ge' -- -x=26 data.txt 

이 또한 쉘 VAR 수

s의 카운트를 포함하려면 특정 단어, 단어 경계 (예 : 단어 주위 \b), 시도 :

perl -spe 's:\bthe\b:$&."(".++$x.")":ge' -- -x=5 data.txt 

결과 :

Now is the(6) time 
for all good men 
to come to the(7) 
aid of their party. 
2

gensub() 여기에 이상적인 소리, 그것은 당신이 N 번째 경기를 교체 할 수 있습니다, 그래서 뭐 해결 방법은 한 번에 한 매치를 바꾸고 j을 증가시키면서 do{}while() 루프의 문자열을 반복하는 것입니다. 이 간단한 gensub() 접근법은 대체 텍스트에 원본 텍스트가 포함되어 있지 않은 경우 (또는 더 나쁜 경우 여러 번 포함) 작동하지 않습니다 (아래 참조). (스티브에 의해 사용되는) 펄의 "s///e"평가 기능, 그 상태 정규식 /g 수정 최고의 나머지 옵션은 덩어리 (머리, 경기로 줄 바꿈하는 것입니다 부족 AWK에 따라서

, 꼬리)와 것은 다시 함께 다시 스틱 :

BEGIN { 
    if (j=="") j=1 
    if (a=="") a="f" 
} 
match($0,a) { 
    str=$0; newstr="" 
    do { 
     newstr=newstr substr(str,1,RSTART-1) # head 
     mm=substr(str,RSTART,RLENGTH)  # extract match 
     sub(a,a"("j++")",mm)     # replace 
     newstr=newstr mm 
     str=substr(str,RSTART+RLENGTH)  # tail 
    } while (match(str,a)) 
    $0=newstr str  
} 
{print} 

이는 epxression 대신 // 패턴이 변수를 사용할 수 있도록로 match()를 사용합니다. (당신은 또한 그냥 "($0 ~ a) { ... }"를 사용할 수 있지만 match()의 결과가이 코드에 사용되는, 그래서 여기에 시도하지 않습니다.)

는 명령 행에 ja을 정의 할 수 있습니다.

gawk 그냥 내가 확실히 아니에요 (유닉스 명령 행에서 추가 이스케이프를 추가하는데주의를 기울여야, perlre의 \b하는 것과 동일 \y을 지원하며, 또한 명시 적으로 단어의 시작과 끝을 맞게 \<\>을 지원합니다 어떤 Windows가 필요하거나 허용 할지도 모름). 위에 언급 된 바와 같이


제한 gensub() 버전

: 여기

match($0,a) { 
    idx=1; str=$0 
    do { 
     prev=str 
     str=gensub(a,a"(" j ")",idx++,prev) 
    } while (str!=prev && j++) 
    $0=str 
} 

문제점은 다음과 같습니다

  • 는 "i" "k"문자열과 하위 문자열 교체하는 경우 또는 "k(1)"다음에 th e gensub() 다음 경기의 색인은 1 씩 해제됩니다. 사전에 알고 있거나 문자열 대신 역순으로 작업하면이 문제를 해결할 수 있습니다.
  • 당신은 "i" "ii"문자열 또는 견고하게 두 조건을 다루는

(gensub() 새로운 일치를 찾는 유지하기 때문에, 무한 루프의 결과로) "ii(i)는"다음에 비슷한 문제가 발생 하위 문자열 대체하는 경우 코드 가치가 없다.

+0

대체품에 원문이 포함되어 있지 않으면이 기능을 사용할 수 없습니다. 이유를 설명하고'gensub()'예제를 제공 할 수 있습니까? 또한 라인에서 첫 번째 일치 항목 만 바꾸려는 경우에는/search/expression에서 변수 "a"를 어떻게 표현할 수 있는지 설명 할 수 있습니까?/?? a ??/{sub (a, a "("++ j ")")} 1'? –

+0

'gensub()'이 추가되었습니다. 위와 같이'match() {...}'를 사용하거나''//''이'($ 0 ~ /)'와 정말로 동일하기 때문에'($ 0 ~ a) {...}'대신에 여기서'a'는 정규 표현식 변수입니다 (변수에는 선행/후행'/'사용하지 않습니다). 캡처 나 다른 것을 필요로하지 않는다면 @ Scrutinizer의 접근 방식은 훨씬 더 간단합니다. –

+0

' "i"를 "k (1)"로 바꾸면 - 변수 "k"를 정의한 곳이 보이지 않거나 문자열 리터럴 인 "k"입니까? –