AWK: 사전의 소스 용어 뒤에 무작위로 선택된 대상 용어 행을 삽입합니다.

AWK: 사전의 소스 용어 뒤에 무작위로 선택된 대상 용어 행을 삽입합니다.

참고: 이미 비슷한 질문을 했습니다.AWK: 소스 용어 뒤에 대상 단어를 삽입하는 빠른 방법그리고 저는 AWK의 초급 수준입니다.

이 문제는 무작위로 선택된 여러 행에서 소스 용어 뒤에 여러 대상 용어를 삽입하는 것을 고려합니다.

이 AWK 코드 조각을 사용하면

awk '(NR==FNR){a[$1];next}
    FNR in a { gsub(/\<source term\>/,"& target term") }
     1
    ' <(shuf -n 5 -i 1-$(wc -l < file)) file

5개의 임의 행 target term뒤에 하나를 삽입하고 싶습니다.source termfile

예: dict왼쪽에 소스 용어가 포함되어 있고 오른쪽에 대상 용어가 포함된 이중 언어 사전이 있습니다.

apple     : Apfel
banana    : Banane
raspberry : Himbeere

광산은 file다음 줄로 구성됩니다.

I love the Raspberry Pi.
The monkey loves eating a banana.
Who wants an apple pi?
Apple pen... pineapple pen... pen-pineapple-apple-pen!
The banana is tasty and healthy.
An apple a day keeps the doctor away.
Which fruit is tastes better: raspberry or strawberry?

첫 번째 단어 apple에 대해 임의의 행 1, 3, 5, 4, 7이 선택되었다고 가정해 보겠습니다. apple이라는 단어가 포함된 출력은 다음과 같습니다.

I love the Raspberry Pi.
The monkey loves eating a banana.
Who wants an apple Apfel pi?
Apple Apfel pen... pineapple pen... pen-pineapple-apple-pen!
The banana is tasty and healthy.
An apple a day keeps the doctor away.
Which fruit is tastes better: raspberry or strawberry?

banana그런 다음 선택될 단어 에 대해 5개의 임의의 라인이 추가됩니다 .

I love the Raspberry Pi .
The monkey loves eating a banana .
Who wants an apple Apfel pi ?
Apple Apfel pen... pineapple pen... pen-pineapple-apple-pen!
The banana Banane is tasty and healthy .
An apple a day keeps the doctor away .
Which fruit is tastes better: raspberry or strawberry?

dict다른 모든 항목은 마지막 항목이 일치할 때까지 계속됩니다 .

무작위로 5개 라인을 선택하고 싶습니다. 줄에 완전한 소스 용어가 있는 경우 전체 단어 apple만 일치시키려고 합니다 ("pineapple"과 같은 용어는 무시됩니다). 예를 들어 한 줄에 소스 용어가 두 번 포함되어 있으면 그 뒤에도 대상 용어를 삽입하고 싶습니다. 일치 항목은 대소문자를 구분해야 하므로 및 같은 소스 용어도 일치시킬 수 있습니다 .ApfelappleappleappleApple

dict내 질문: 사전을 사용할 수 있고 사전을 선택할 수 있도록 위의 코드 조각을 어떻게 다시 작성합니까?무작위의행을 클릭 file하고 소스 용어 뒤에 대상 용어를 삽입하시겠습니까?

답변1

다음은 awk를 사용하여 입력 파일에서 5개의 줄 번호를 무작위로 선택하는 방법입니다(첫 번째 패스에서 wc를 사용하면 줄 번호만 계산됩니다).

$ awk -v numLines="$(wc -l < file)" 'BEGIN{srand(); for (i=1; i<=5; i++) print int(1+rand()*numLines)}'
7
2
88
13
18

이제 가져가기만 하면 된다내 이전 답변블록에서 읽은 각 "이전" 문자열에 대해 ARGIND==1위에 표시된 대로 5개의 줄 번호를 생성하고 배열을 채우고 생성된 줄 번호를 각 줄 번호와 관련된 이전 문자열에 매핑한 다음 파일을 읽습니다. 마지막으로 파일이 입력되면 확인합니다. 줄 번호가 현재 배열에 있고 그렇다면 해당 줄 번호에 대해 배열에 저장된 "이전"을 반복하여 gsub()이전 답변에서 보여준 작업을 수행합니다.

ARGIND, IGNORECASE, 단어 경계, 배열의 배열 및 : 의 \s약어를 나타내려면 GNU awk를 사용하십시오.[[:space:]]

$ cat tst.sh
#!/usr/bin/env bash

awk -v numLines=$(wc -l < file) '
    BEGIN {
        FS = "\\s*:\\s*"
        IGNORECASE = 1
        srand()
    }
    ARGIND == 1 {
        old = "\\<" $1 "\\>"
        new = "& " $2
        for (i=1; i<=5; i++) {
            lineNr = int(1+rand()*numLines)
            map[lineNr][old] = new
        }
        next
    }
    FNR in map {
        for ( old in map[FNR] ) {
            new = map[FNR][old]
            gsub(old,new)
        }
    }
    { print }
' dict file

$ ./tst.sh
I love the Raspberry Pi.
The monkey loves eating a banana Banane.
Who wants an apple Apfel pi?
Apple Apfel pen... pineapple pen... pen-pineapple-apple Apfel-pen!
The banana Banane is tasty and healthy.
An apple a day keeps the doctor away.
Which fruit is tastes better: raspberry Himbeere or strawberry?

답변2

확장 정규식 모드(-E) 및 s/// 명령의 (/e) 수정자를 사용하는 GNU sed:

n=$(< file wc -l)
sed -E '/\n/ba
  s#^(\S+)\s*:\s*(\S+)$#s/\\<\1\\>/\& \2/Ig#;h'"
  s/.*/shuf -n 5 -i '1-$n'/e;G
  :a
  s/^([0-9]+)(\n.*\n(.*))/\1 \3\2/
  /\n.*\n/!s/\n/ /
  P;D
" dict | sed -f /dev/stdin file

  • 덕트 파일의 내용에서 GNU sed 명령을 생성합니다.
  • 명령을 보류 상태로 저장합니다.
  • 주사위를 굴려 입력 파일의 줄 길이 내에서 5개의 난수를 생성합니다.
  • 보존 모드를 고수하고 이러한 특정 라인에서만 실행되는 sed 명령을 생성하십시오.
  • 입력 파일에 생성된 다음 명령을 적용합니다.

관련 정보