일련의 sed 명령은 명령 행에서 작동하지만 스크립트에서는 작동하지 않습니다. “”id””: 281952, “”title””: “”Flash 11.2

이 SE 데이터 쿼리.csv출력을 다음 과 같이 출력 하고 있습니다 (5022 항목 만 해당).

"{
  ""id"": 281952,
  ""title"": ""Flash 11.2 No Longer Supported by Google Play""
}"
"{
  ""id"": 281993,
  ""title"": ""Netbeans won't open in Ubuntu""
}"

(그리고 ^M[number]와 “”title “”사이에 줄 끝이 있습니다). 다음과 같이 표시해야합니다.

281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

나는 이것을 꽤 쉽게 이름이 남지 않는 특정 텍스트 편집기에서 수정했지만 쿼리를 새로 고칠 때마다 다시 할 필요가 없도록 다른 스크립트를 사용할 수 있도록 스크립트를 만들고 싶었습니다. 나는 사용했다 sed

이 일련의 명령은 완벽하게 작동합니다 (비효율적이지만 시행 착오 솔루션 일뿐입니다).

# Print the ^M and remove them, write to a new file:
cat -v QueryR* | sed 's/\^M//' > QueryNew
# remove all the other junk:
sed -i 's/{//' QueryNew
sed -i 's/}//' QueryNew
sed -i 's/""//g' QueryNew
sed -i 's/^"//' QueryNew
sed -i '/,/{N;/\n.*title:\s/{s/,\n.*title:\s/,\ /}}' QueryNew
sed -i 's/^\s\+//' QueryNew
sed -i '/^\s*$/d' QueryNew
sed -i 's/^id:\ //' QueryNew
sed -i 's/,\ /,/' QueryNew
sed -i 's/\\//g' QueryNew

그렇다면 왜 그렇지 않습니까? ^Mand 만 {}제거하면 나머지는 여전히 존재합니다.

#!/bin/bash
cat -v QueryR* | sed 's/\^M//' > QueryNew
sed -i '{
       s/{//
       s/}//
       s/""//g
       s/^"//
       /,/{N;/\n.*title:\s/{s/,\n.*title:\s/,\ /}}
       s/^\s\+//
       /^\s*$/d
       s/^id:\ //
       s/,\ /,/
       s/\\//g
}' QueryNew

내 실수가 정말 분명하다고 확신합니다 …



답변

사용 cat -v문자에 CR 문자를 설정하는 ^M시퀀스 것은 나에게 근본적으로 추한 것 – 당신이 DOS 라인 엔딩 사용을 제거해야하는 경우 dos2unix, tr또는 sed 's/\r$//

sed를 사용한다고 주장하면 원하지 않는 모든 임의의 비트를 삭제하지 않고 원하는 비트를 인쇄하는 것이 좋습니다.

$ sed -rn -e 's/\"//g' -e 's/(.*): (.*)\r/\2/p' QueryR | paste -d '' - -
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

값 시퀀스의 각 끝에서 0 개 이상의 따옴표를 일치시켜 따옴표를 제거하여 키-값 추출로 롤백 할 수 있습니다.

$ sed -rn 's/(.*): \"*([^"]*)\"*\r/\2/p' QueryR | paste -d '' - -
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

당신이 얻을 수있는 정말 멋진을하고 에뮬레이션 paste에서 sed처음에 라인 쌍을 결합하여 ,\r$종료 한 후 다중 키 – 값 쌍을 일치 ( g) 및 비 탐욕

$ sed -rn '/,\r$/ {N; s/([^:]*): \"*([^:"]*)\"*\r\n?/\2/gp}' QueryR
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

(개인적으로 KISS 접근 방식을 선호하고 첫 번째 접근 방식을 사용합니다).


FWIW, 입력이 초과 인용 된 것으로 보이므로 적절한 JSON 파서를 설치하는 것이 좋습니다. jq

sudo apt-get install jq

그런 다음 같은 것을 할 수 있습니다

$ sed -e 's/["]["]/"/g' -e 's/"{/{/' -e 's/}"/}/' QueryR | jq '.id, .title' | paste -d, - -
281952,"Flash 11.2 No Longer Supported by Google Play"
281993,"Netbeans won't open in Ubuntu"

불필요한 따옴표를 제거한 다음 jq관심있는 필드를 추출하는 데 사용 jq합니다. DOS 스타일 줄 끝을 처리 하는 것으로 보이므로 제거하기 위해 특별한 단계를 수행 할 필요가 없습니다.

jq '.[]'모든 속성 값 쌍을 덤프 하도록 변경하십시오 .

grep -o를 사용하여 줄 바꿈 극복jq 에서
얻은 영감과 기본 구문에 대한 크레딧


답변

나는 스틸 드라이버 및 추가 땜질 덕분에 고쳤습니다. 정제되지 않았지만 작동합니다.

sed  '{
       s/"{//
       s/}"//
       s/^"//
       /,\r/{N;/\n.*title.*:\s/{s/,\r\n.*title.*:\s/,/}}
       s/""//g
       s/^\s\+//
       /^\s*$/d
       s/^id:\ //
       s/\\//g
}' QueryR* | tee "$1"

번역 :
s/"{//제거 "{
s/}"//제거 }"
s/^"//제거 "라인의 시작부터
/,\r/{N;/\n.*title.*:\s/{s/,\r\n.*title.*:\s/,\ /}}경기를 ,\r한 줄에와 [whatever]title[whatever]:다음 라인은, 함께하는 모든 교체 ,
s/""//g남아있는 모든 이중 따옴표를 제거
s/^\s\+//라인의 시작부터 제거 공백을
/^\s*$/d빈 줄이 제거
s/^id:\ //제거 id:는 후 공간
s/\\//g백 슬래시를 제거하기위한 (이스케이프 문자를 “(일부 제목 필드에 추가됨)
tee "$1"스크립트를 실행할 때 출력 파일을 지정하십시오 (예 :./queryclean newquery.csv


답변

질문은을 요구하지만 sedPython과 함께 sed의 문제를 해결할 수 있습니다.

from __future__ import print_function
import sys

with open(sys.argv[1]) as f:
     for line in f:
         if '""id""' in line:
            print(line.strip().split(':')[1],end="")
         if '""title""' in line:
            title = " ".join(line.strip().split(':')[1:])
            print(title.replace('""'," "))

이 코드는 python2 및 python3 모두와 호환되므로 어느 쪽이든 작동합니다.

샘플 실행 :

bash-4.3$ cat questions.txt
"{
  ""id"": 281952,
  ""title"": ""Flash 11.2 No Longer Supported by Google Play""
}"
"{
  ""id"": 281993,
  ""title"": ""Netbeans won't open in Ubuntu""
}"
bash-4.3$ python3 parse_questions.py questions.txt
 281952,  Flash 11.2 No Longer Supported by Google Play
 281993,  Netbeans won't open in Ubuntu 


답변

세 가지 접근 방식 :

  1. 어 wk

    $ awk -F'": ' '/\"id\"/{id=$NF;}
                  /\"title\"/{
                    t=$NF;
                    sub(/^""/,"",t);
                    sub(/""$/,"",t);
                    print id,t
                  }' OFS="" file
    281952,Flash 11.2 No Longer Supported by Google Play
    281993,Netbeans won't open in Ubuntu
  2. $ perl -lne '$id=$1 if /id"":\s*(\d+)/;
                 if(/title"":\s*""(.*)""/){print "$id,$1"}' file
    281952,Flash 11.2 No Longer Supported by Google Play
    281993,Netbeans won't open in Ubuntu
  3. 펄 호환 정규식과 간단한 펄이있는 GNU grep :

    $ grep -oP '(id"":\s*\K.*)|(title"":\s*""\K.*(?=""))' file |
        perl -pe 'chomp if $.%2'
    281952,Flash 11.2 No Longer Supported by Google Play
    281993,Netbeans won't open in Ubuntu

답변

이것은 정확히 질문에 대답하거나 문제를 해결하는 것이 아니라 원하지 않는 문자를 제거하려면 tr 을 사용할 수 있습니다 .

cat QueryR | tr -d '}{:"' 

그리고 당신은 얻을 것이다 :

여기에 이미지 설명을 입력하십시오


답변

이것은 루비로 작성된 또 다른 스크립트입니다. 제목을 쉼표로 유지하므로 열을 손상시키지 않고 스프레드 시트 프로그램으로 쉽게 가져올 수 있습니다.

csvfile = File.open('query-fixed.csv', 'w')

File.open('QueryResults2.csv') do |f|
    content = f.read
    content.gsub!(/\r\n?/, "\n")
    content.each_line do |line|
        id, title = '', ''
        if line.match('\"id\"')
            id = line.split(':')[1].strip[0..-2]
            csvfile.write(id + ',')
        end
        if line.match('\"title\"')
            title = line.partition(':')[2].scan(/"(.*)"/)[0][0]
            csvfile.write(title + "\n")
        end
    end
end

프로그램이 실행 된 후 생성 된 출력은 다음과 같습니다.

281952,"Flash 11.2 No Longer Supported by Google Play"
281993,"Netbeans won't open in Ubuntu"


답변