공백이 포함된 텍스트 열을 1개의 필드로 처리

공백이 포함된 텍스트 열을 1개의 필드로 처리

다음 형식의 파일이 있습니다.
INTEGER INTEGER TEXT

텍스트는 유니코드이며 공백을 포함할 수 있습니다.
printf를 사용하여 파일의 첫 번째 INTEGER 및 TEXT를 특정 형식으로 인쇄하기 위해 awk를 사용하려고 합니다.
문제: 일부 줄의 TEXT에 공백이 있으므로 $3에는 완전한 TEXT가 없으므로 더 많은 필드에서 줄이 손상됩니다.

예:

12 42956    Cinema - 3D/Multiplex  
7  12560    Status Update  
5  184   Movie  

내 접근 방식은 다음과 같습니다.

awk '{ c=$3; for(i=4; i< NF;++i){c=c" "$i}; printf "<tag>%d</tag>\n<tag>%s</tag>\n", $1,c}';  

하지만 더 좋은 방법이 있을 것 같아요

답변1

awk데이터가 명확하게 지정된 레코드에서 나온 경우 유용합니다. 이 데이터는 사용할 수 없습니다. 그러나 데이터는 " integer stuff the_rest" 형식이며 " integer" 또는 " " stuff에 공백이 없습니다 . 이것이 바로 read유틸리티가 읽고 싶어하는 것입니다. 읽도록 지정한 변수만큼 공백으로 구분된 단어를 읽은 다음 줄의 "나머지"를 마지막 변수에 넣습니다.

bash-4.4$ while read -r integer stuff the_rest; do printf '%d\t"%s"\n' "$integer" "$the_rest"; done <data
12      "Cinema - 3D/Multiplex"
7       "Status Update"
5       "Movie"

모든 후행 공백을 자동으로 제거합니다.

답변2

스키마를 기반으로 필드를 추출하는 것이 perl다음보다 나은 경우가 많습니다 awk.

perl -lne '
  if (/^\s*(\d+)\s*\S+\s*(.*?)\s*$/) {
    print "<tag>$1</tag><tag>$2</tag>"
  }'

귀하의 의견은 다음을 제공합니다.

<tag>12</tag><tag>Cinema - 3D/Multiplex</tag>
<tag>7</tag><tag>Status Update</tag>
<tag>5</tag><tag>Movie</tag>

이는 필요한 경우 적절한 HTML 인코딩과 같은 고급 작업을 수행할 수 있음을 의미합니다. 예를 들면 다음과 같습니다.

perl -Mopen=locale -MHTML::Entities -lne '
  if (/^\s*(\d+)\s*\S+\s*(.*?)\s*$/) {
    print map {"<tag>" . encode_entities($_) . "</tag>"} $1, $2
  }'

또는 XML 인코딩:

perl -Mopen=locale -MXML::LibXML -lne '
  if (/^\s*(\d+)\s*\S+\s*(.*?)\s*$/) {
    print map {
      my $e = XML::LibXML::Element->new("tag");
      $e->appendText($_);
      $e->toString} $1, $2
  }'

답변3

$2(어쨌든 사용하지 않음)를 사용되지 않은 문자(문자열에 존재하지 않는 문자)로 바꿉니다. 그 후에는 다음을 수행하세요.

awk '{$2="+";print}' input-file.txt | awk -F "+" '{printf "<tag>%d</tag>\n<tag>%s</tag>\n",$1,$2}'

위에서는 더하기 기호 "+"를 구분 기호로 사용했습니다.

가장 우아한 해결책은 아니지만 간단합니다.

답변4

이것이 큰 파일이 아니고 텍스트가 항상 끝에 있으므로 대안으로 다음과 같은 고전적인 bash 접근 방식을 사용하는 것을 고려할 수 있습니다.

while IFS=' ' read -r int1 int2 text;do
#do your stuff
done <file

while - read의 경우와 마찬가지로 read 명령의 마지막 var $text는 나머지 모든 필드를 하나의 필드로 가져옵니다.

시험:

$ IFS=' ' read -r int1 int2 text <<<"10 5 some text here"
$ echo "$text"
some text here

읽는 동안 Bash는 대용량 데이터 파일에서 상당히 느릴 수 있지만 귀하의 경우에는 시도해 볼 수 있습니다.

관련 정보