필드와 부분 문자열을 추출하고 정렬된 행을 병합합니다.

필드와 부분 문자열을 추출하고 정렬된 행을 병합합니다.

탭으로 구분된 5개의 필드로 구성된 파일이 있습니다(이 경우 관련 없는 필드는 비어 있습니다).

1       2       URL                     email               5

                https://www.a.com/t     [email protected]
                https://www.a.com       [email protected]
                https://www.b.fr        [email protected]
                https://www.b.fr/s/faq  [email protected]

원하는 출력:

domain          email(s)    
        
a.com           [email protected]
b.fr            [email protected], [email protected]

속도:

  1. 열 3과 4를 분리합니다.
awk -F "\t" '{print $3 "\t\t" $4}' 

그러면 위의 첫 번째 블록에 표시된 내용이 생성됩니다.

어떻게 진행하나요?

나는 필드를 grep하는 방법만 알고 있지만 필드를 분리하는 것은 원하는 출력 라인을 얻는 데 큰 도움이 되지 않습니다.

나는 이것에만 국한되지 않고 awk, (플래그를 통해) 필드를 쉽게 분리할 수 있는 내가 아는 유일한 도구일 뿐입니다 -F.

답변1

awkGNU 사용 datamash:

awk 'BEGIN{ OFS=FS="\t" }
  NR>2{                       # skip first two records
    split($3, a, "/" )        # split $3 into array a on /
    domain=a[3]               # 3rd element is the domain name
    sub(/^www\./, "", domain) # remove www. prefix
    print domain, $4          # print domain and email
  }
' file | datamash -g 1 unique 2

awk섹션에서는 처음 두 줄을 건너뛰고 모든 기록에 대한 도메인과 이메일을 인쇄합니다. 이것은 ~이 될 것이다

a.com   [email protected]
a.com   [email protected]
b.fr    [email protected]
b.fr    [email protected]

그런 다음 출력은 datamash첫 번째 필드로 파이프되어 입력을 그룹화하고 두 번째 필드에 대한 고유 값의 쉼표로 구분된 목록을 인쇄합니다.

산출:

a.com   [email protected]
b.fr    [email protected],[email protected]

제목 줄은 연습용으로 예약되어 있습니다.

답변2

GNU awk를 사용하여 배열의 배열 합계를 처리합니다 gensub().

$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR>1 { d2e[gensub(/[^.]+\.([^.]+\.[^./]+).*/,"\\1",1,$3)][$4] }
END {
    print "domain", "emails(s)"
    for (domain in d2e) {
        cnt = 0
        for (email in d2e[domain]) {
            row = (cnt++ ? row ", " : domain OFS) email
        }
        print row
    }
}

$ awk -f tst.awk file
domain  emails(s)
a.com   [email protected]
b.fr    [email protected], [email protected]

답변3

사용밀러(sed의 도움으로):

$ mlr --prepipe 'sed "/^$/d"' --tsv   put -q -S '
  $domain = joinv(mapexcept(splitnvx(joinv(mapselect(splitnvx($URL,"/"),3),""),"."),1),".");
  @e[$domain] = mapsum(@e[$domain],{$email:1});
  end {
    for(k,v in @e){@{email(s)}[k] = joink(v,",")};
    emit @{email(s)}, "domain"
  }' File.tsv
domain  email(s)
a.com   [email protected]
b.fr    [email protected],[email protected]

sed --prepipe명령은 입력이 TSV로 구문 분석될 수 있도록 불필요한 빈 줄을 제거합니다. 변수 $domainURL필드를 먼저 /(세 번째 요소 선택) 분할한 다음 .(첫 번째 요소를 제외한 모든 요소 선택, 예를 들어 www) 두 번 분할하여 얻습니다. 그런 다음 스트림 외부 매핑은 다음 @e과 같이 구성 됩니다.지도필드 수 email– 동일한 도메인에서 중복된 이메일을 제거하는 단계입니다. 에서 end이메일 맵을 쉼표로 구분된 문자열로 변환하고 내보냅니다.

답변4

이 문제는 세 번째 필드(실제로 그 일부)를 키로 사용하고 set네 번째 필드가 포함된 해당 값을 사용하여 사전을 구성하면 해결될 수 있습니다. a의 유용성 set은 요소를 본질적으로 고유하게 유지하므로 값을 고유하게 유지하기 위해 어떤 종류의 프로그래밍 연습에도 노력을 기울일 필요가 없다는 것입니다.

python3 -c 'import sys
ifile = sys.argv[1]
fs = ofs = "\t"
d = {}

with open(ifile) as fh:
  for i,l in enumerate(fh,1):
    if i < 3: continue
    x,x,y,email,x = l.split(fs)
    domain = y.split("/")[2].split(".",1)[1]
    if domain in d:
      d[domain].add(email)
    else:
      d[domain] = { email }

print(f"domain{ofs}email(s)",
      *[k+ofs+", ".join(v) for k,v in d.items()],
      sep="\n")
' file
domain  email(s)
a.com   [email protected]
b.fr    [email protected], [email protected]

관련 정보