jq를 사용하여 CSV에서 값 및 형식 추출


57

아래 JSON 파일이 있습니다.

{
"data": [
    {
        "displayName": "First Name",
        "rank": 1,
        "value": "VALUE"
    },
    {
        "displayName": "Last Name",
        "rank": 2,
        "value": "VALUE"
    },
    {
        "displayName": "Position",
        "rank": 3,
        "value": "VALUE"
    },
    {
        "displayName": "Company Name",
        "rank": 4,
        "value": "VALUE"
    },
    {
        "displayName": "Country",
        "rank": 5,
        "value": "VALUE"
    },
]
}

이 형식의 CSV 파일을 갖고 싶습니다.

First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE, VALUE

이것을 사용하여 가능 jq합니까? 프로그래밍 기술이 없습니다.


1
아래에 답변을 제공했지만 이제 귀하의 질문을 자세히 살펴보고 있습니다. 궁금한 점이 없습니다. 6 번째 VALUE의 출처는 어디 입니까?
mikeserv


답변:


49

jq에는 배열을 CSV 문자열로 변환하기위한 @csv 필터가 있습니다. 이 필터는 필드에 포함 된 쉼표로 시작하여 CSV 형식과 관련된 대부분의 복잡성을 고려합니다. (jq 1.5에는 탭으로 구분 된 값 파일을 생성하기위한 @tsv와 유사한 필터가 있습니다.)

물론 헤더와 값에 모두 쉼표와 큰 따옴표가없는 경우에는 @csv 필터를 사용할 필요가 없습니다. 그렇지 않으면 아마도 그것을 사용하는 것이 좋습니다.

예를 들어 '회사 이름'이 'Smith, Smith and Smith'이고 다른 값이 아래에 표시된 경우 "-r"옵션으로 jq를 호출하면 유효한 CSV가 생성됩니다.

$ jq -r '.data | map(.displayName), map(.value) | @csv' so.json2csv.json
"First Name","Last Name","Position","Company Name","Country"
"John (""Johnnie"")","Doe","Director, Planning and Posterity","Smith, Smith and Smith","Transylvania"

3
나는 무언가를 'jq 할 수 있었다 | 지도 (.) | @csv ', 매우 편리합니다! 감사합니다
flickerfly

3
예를 들어 레코드 당 한 줄씩 표시하는 대신 모든 표시 이름을 첫 번째 줄에, 모든 값을 두 번째 줄에 넣습니다.
Brian Gordon

32

CSV에서 각 레코드를 행으로 만들고 싶습니다.

jq '.data | map([.displayName, .rank, .value] | join(", ")) | join("\n")'

2
.value가 숫자이면 어떻게 되나요? "문자열 및 숫자를 추가 할 수 없습니다"라는 오류가 표시됩니다.
Cos

2
같은 @Cos .value|tostring대신 .value위의 예
matheeeny

4
@Cos, 괄호가 필요하다는 것을 알았습니다. (.value|tostring)
ciscogambo

또한 jq -r따옴표를 제거하는 데 사용
Clay

30

이 파일 만 있으면 다음과 같은 작업을 수행 할 수 있습니다.

<testfile jq -r '.data | map(.displayName), map(.value) | join(", ")'

.연산자 개체 / 해시의 필드를 선택한다. 따라서 .data데이터로 배열을 반환하는로 시작 합니다. 그런 다음 배열에 두 번 매핑하여 먼저 displayName을 선택한 다음 값을 선택하면 해당 키 값만으로 두 개의 배열이 제공됩니다. 각 배열에 대해 요소를 ","로 결합하여 두 줄을 만듭니다. -r인수는 말한다 jq결과 문자열을 인용하지.

실제 파일이 더 길면 (즉, 둘 이상의 사람에 대한 항목이있는 경우) 좀 더 복잡한 것이 필요할 수 있습니다.


그것은 나를 위해 작동하지 않습니다. 관련 주제에서 답변 stackoverflow.com/questions/32960857/… 은 작동하고 잘 설명되어 있습니다!
herve

10

나는 jq내 머리를 감싸기 힘들었다. 다음은 루비입니다.

ruby -rjson -rcsv -e '
  data = JSON.parse(File.read "file.json")
  data["data"].collect {|item| [item["displayName"], item["value"]]}
              .transpose
              .each {|row| puts row.to_csv}
'
First Name,Last Name,Position,Company Name,Country
VALUE,VALUE,VALUE,VALUE,VALUE

루비 JSON 파서는 닫는 괄호 앞에 쉼표를 표시합니다.


2

이것을 태그 python하고 json파일 이름을 가정하면x.json

import os, json
with open('x.json') as f:
    x  = json.load(f)
    print '{}{}{}'.format(', '.join(y['displayName'] for y in x['data']), os.linesep,
             ', '.join(y['value'] for y in x['data']))
First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE

1

jq다른 배열 요소를 기대하는 것에 대해 불평 했기 때문에 예제 입력에서 마지막 쉼표를 제거해야 작동했지만 다음과 같습니다.

INPUT | jq -r '[.[][].displayName], [.[][].value]| join(", ")'

...저를 얻었다...

First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE

간단히 말해서 작동 방식 :

  1. []인덱스 필드 형식과 .dot표기법을 사용하여 세 번째 수준의 데이터 개체를 탐색했습니다 .
  2. 충분히 깊이 들어가서 원하는 이름으로 데이터 필드를 지정했습니다 .[][].displayName.
  3. 원하는 필드가 다음과 같은 별도의 배열 객체로 반환되어 자체 연관되어 있음을 확신했습니다. [.[][].displayName], [.[][].value]
  4. 그런 다음 해당 객체를 join(", ")함수에 파이프하여 별도의 엔터티로 결합되었습니다.

실제로 수행하는 [.field]것은 또 다른 방법 map(.field)이지만 원하는 데이터를 검색하기위한 깊이 수준을 지정한다는 점에서 조금 더 구체적입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.