jq를 사용하여 CSV에서 JSON으로
다음과 같은 csv 데이터 세트가 있는 경우:
name, age, gender
john, 20, male
jane, 30, female
bob, 25, male
당신은 이것을 이해할 수 있습니까?
[ {"name": "john", "age": 20, "gender": "male"},
{"name": "jane", "age": 30, "gender": "female"},
{"name": "bob", "age": 25, "gender": "male"} ]
jq만 사용하시겠습니까?
내가 하려는 일을 보여주는 이 문서를 찾았는데, 이 문서는 헤더 필드의 값에 대한 '수동' 매핑을 사용합니다.헤더 필드의 이름을 변경할 필요가 없거나 헤더 필드의 수가 상당히 많습니다.레이아웃이 변경될 때마다 스크립트/명령어를 변경할 필요도 없습니다.
헤더를 동적으로 추출한 다음 jq 원라이너로 값과 결합할 수 있습니까?
간단히 말해서, 네, 단 한 줄만 빼고요.
jq는 종종 텍스트 논쟁에 잘 대응하며, 이는 regex를 지원하는 버전에 특히 해당됩니다.예를 들어 regex를 지원하는 경우 지정된 문제 설명서에서 요구하는 트리밍은 매우 간단합니다.
jq 1.5rc1은 정규식을 지원하며 2015년 1월 1일부터 사용 가능하므로 다음 프로그램은 jq 1.5 버전을 가정합니다. jq 1.4와 함께 작동하려면 두 개의 "jq 1.4용" 주석을 참조하십시오.
또한 이 프로그램에서는 CSV의 모든 일반성과 복잡성에 대해 다루지 않습니다(CSV를 보다 일반적으로 다루는 유사한 접근법에 대해서는 https://github.com/stedolan/jq/wiki/Cookbook#convert-a-csv-file-with-headers-to-json)를 참조하십시오.
# objectify/1 takes an array of string values as inputs, converts
# numeric values to numbers, and packages the results into an object
# with keys specified by the "headers" array
def objectify(headers):
# For jq 1.4, replace the following line by: def tonumberq: .;
def tonumberq: tonumber? // .;
. as $in
| reduce range(0; headers|length) as $i ({}; .[headers[$i]] = ($in[$i] | tonumberq) );
def csv2table:
# For jq 1.4, replace the following line by: def trim: .;
def trim: sub("^ +";"") | sub(" +$";"");
split("\n") | map( split(",") | map(trim) );
def csv2json:
csv2table
| .[0] as $headers
| reduce (.[1:][] | select(length > 0) ) as $row
( []; . + [ $row|objectify($headers) ]);
csv2json
예(csv.csv가 지정된 CSV 텍스트파일이라고 가정합니다).
$ jq -R -s -f csv2json.jq csv.csv
[
{
"name": "john",
"age": 20,
"gender": "male"
},
{
"name": "jane",
"age": 30,
"gender": "female"
},
{
"name": "bob",
"age": 25,
"gender": "male"
}
]
With Miller(http://johnkerl.org/miller/doc/)는 매우 간단합니다.이 input.csv 파일 사용
name,age,gender
john,20,male
jane,30,female
bob,25,male
및 실행 중
mlr --c2j --jlistwrap cat input.csv
당신은 갖게 될 것이다
[
{ "name": "john", "age": 20, "gender": "male" }
,{ "name": "jane", "age": 30, "gender": "female" }
,{ "name": "bob", "age": 25, "gender": "male" }
]
편집
이것은 오래된 질문입니다.새로운 문서 페이지는 https://miller.readthedocs.io/en/latest/ 입니다.
2018년은 Python tool 을 사용하는 입니다.csvkit
있다csvjson data.csv > data.json
.
매뉴얼을 참조하십시오.https://csvkit.readthedocs.io/en/1.0.2/
입니다.jq
가 양쪽 모두를 csv
★★★★★★★★★★★★★★★★★」json
포맷을 지정합니다.
또한 visidata라는 강력한 도구를 확인하는 것이 좋습니다.오리지널 포스터와 유사한 스크린캐스트 사례 연구를 소개합니다.스크립트를 생성할 수도 있습니다.visidata
조금 놀다가 이걸 생각해 냈어요.하지만 그게 최선의 방법은 아닐 수도 있고, 당신의 시도가 어땠는지 알고 싶습니다. 왜냐하면 결국 우리 둘 다 해결책을 찾는다면 두 배 더 좋을 것이기 때문입니다.
하지만 이런 것부터 시작하죠.
true as $doHeaders
| . / "\n"
| map(. / ", ")
| (if $doHeaders then .[0] else [range(0; (.[0] | length)) | tostring] end) as $headers
| .[if $doHeaders then 1 else 0 end:][]
| . as $values
| keys
| map({($headers[.]): $values[.]})
''$doHeaders
는 맨 위 행을 헤더 행으로 읽을지 여부를 제어합니다.고객님의 경우에는 사실이지만 미래의 SO 사용자를 위해 추가했습니다.오늘 아침 식사는 훌륭하고 날씨도 좋기 때문에, 왜 안 될까요?
간단한 설명:
1). / "\n"
★★★★★★★★★★★...
2)map(. / ", ")
...와 쉼표(Big gotcha:버전에서는 regex 기반 분할을 사용하는 것이 좋습니다.따옴표 안에서도 콤마로 분할되기 때문입니다.간단하기 때문에 사용한 것입니다.솔루션이 멋있어 보이죠?)
3)if $doHeaders then...
서는 첫 의 수와 첫 행인지키합니다.
4).[if $doHeaders then 1 else 0 end:]
이면 맨 , 머리글이면 잘라내.
5)map({($headers[.]): $values[.]})
의 각 하고 csv를 합니다.$values
키는 변수로, 키는 파이프로 변환됩니다.런음
물론 당신은 몇 개의 정규식을 사용하여 고차(gottchas)를 채우고 싶겠지만, 저는 그것이 당신을 시작하기를 바랍니다.
yq(내가 작성한 청구인)는 즉시 이를 지원합니다.
yq file.csv -p=csv -o=json
수율:
[
{
"name": "john",
" age": 20,
" gender": "male"
},
{
"name": "jane",
" age": 30,
" gender": "female"
},
{
"name": "bob",
" age": 25,
" gender": "male"
}
]
원래 CSV의 열 2와 3에 선행 공백이 있습니다.실수인지 아닌지 확실하지 않습니다.식을 추가하여 트리밍할 수 있습니다.
yq '(... | select(tag == "!!str")) |= trim' file.csv -p=csv -o=json
이 값은 모든 문자열과 트리밍 선행 공간과 일치하므로 다음과 같은 결과가 됩니다.
[
{
"name": "john",
"age": 20,
"gender": "male"
},
{
"name": "jane",
"age": 30,
"gender": "female"
},
{
"name": "bob",
"age": 25,
"gender": "male"
}
]
를 ''는 'jq'와 함께 실행한다고 .-s
★★★★★★★★★★★★★★★★★」-R
★★★★★★★★★★★★★★★★★★.
[
[
split("\n")[] # transform csv input into array
| split(", ") # where first element has key names
| select(length==3) # and other elements have values
]
| {h:.[0], v:.[1:][]} # {h:[keys], v:[values]}
| [.h, (.v|map(tonumber?//.))] # [ [keys], [values] ]
| [ transpose[] # [ [key,value], [key,value], ... ]
| {key:.[0], value:.[1]} # [ {"key":key, "value":value}, ... ]
]
| from_entries # { key:value, key:value, ... }
]
샘플 실행:
jq -s -R -f filter.jq data.csv
출력 예시
[
{
"name": "john",
"age": 20,
"gender": "male"
},
{
"name": "jane",
"age": 30,
"gender": "female"
},
{
"name": "bob",
"age": 25,
"gender": "male"
}
]
다음은 jq의 "합리적인" 크기의 파일에 사용할 수 있는 매우 단순한 "한 줄" 버전입니다. 매우 큰 파일에는 slurp를 사용하지 않는 버전이 필요합니다.저는 jq에 대해 잘 모르기 때문에 더 나은 방법이 있을 것입니다(데이터에 저장하는 대신 인덱스 값만 입력).더 짧고 읽기 어렵게 하려면 "split"을 ./"\n" 및 ./"로 대체할 수 있습니다.메모: 콤마가 ", " 또는 콤마 분할 후에 |map("gsub("^\s+|\s+$")")로 분할된 후 공간이 필요한 경우 선행 및 후행 공백을 잘라냅니다.
jq -Rs 'split("\n")|map(split(",")|to_entries)|.[0] as $header|.[1:]|map(reduce .[] as $item ({};.[$header[$item.key].value]=$item.value))'
다음은 코멘트된 버전입니다.
# jq -Rs
split("\n") | map( split(",") | to_entries ) # split lines, split comma & number
| .[0] as $header # save [0]
| .[1:] # and then drop it
| map( reduce .[] as $item ( {}; .[$header[$item.key].value] = $item.value ) )
맨 위 부분은 매우 간단합니다.새로운 행으로 데이터를 분할한 후 콤마로 분할한 각 요소에 대해 to_entries가 키 번호(0)를 붙여 키/값 엔트리로 변환합니다.N): {key:#, value:string}
그런 다음 map/reduce를 사용하여 각 요소를 가져와서 숫자 키를 사용하여 키/값 쌍의 개체로 대체하고 헤더에 다시 인덱스를 작성하여 레이블을 가져옵니다.(저와 같은) 새로운 사용자에게는 세미콜론까지의 첫 번째 요소는 '어큐뮬레이터'(요소 위의 각 패스를 수정하는 것)를 초기화하는 것입니다.그러면 .[...]는 어큐뮬레이터를 수정하고 $item은 우리가 조작하는 오브젝트입니다.
업데이트: slurp를 사용하지 않는 더 나은 버전이 출시되었으며, 첫 번째 줄을 특별히 처리하므로 -n 옵션은 사용하지 않습니다.
jq -R 'split(",") as $h|reduce inputs as $in ([]; . += [$in|split(",")|. as $a|reduce range(0,length) as $i ({};.[$h[$i]]=$a[$i])])'
구문을 줄이지 않고 실행할 수도 있습니다.
#! /bin/jq -fRs
split("\n")|map(select(.!="")|split(","))
|.[0] as $headers
|.[1:][]
|with_entries(.key=$headers[.key])
최근에 비슷한 일을 한 적이 있는데, 여기 또 있습니다.jq
CSV를 JSON 어레이로 변환하는 원라이너입니다.
jq --null-input --raw-input '[input|scan("\\w+")] as $header |[inputs as $data |[$header,[$data|scan("\\w+")|tonumber? // .]] |transpose |map({(.[0]):.[1]}) |add]' input.csv
출력, 입력 예:
[
{
"name": "john",
"age": 20,
"gender": "male"
},
{
"name": "jane",
"age": 30,
"gender": "female"
},
{
"name": "bob",
"age": 25,
"gender": "male"
}
]
jqplay.org 에서 시험해 보세요.
언급URL : https://stackoverflow.com/questions/29663187/csv-to-json-using-jq
'source' 카테고리의 다른 글
Azure 함수에서 JSON을 반환하는 방법 (0) | 2023.02.22 |
---|---|
키워드 제목, 내용 또는 태그에 존재하는 경우 Word press get_posts (0) | 2023.02.22 |
WPML의 "String translation"에 문자열이 표시되지 않는 이유는 무엇입니까? (0) | 2023.02.22 |
스프링 부츠 + 스프링 탑재 (IntelliJ, Gradle) (0) | 2023.02.22 |
postgresql 9.3에서 JSON 어레이를 루프하는 방법 (0) | 2023.02.22 |