iT邦幫忙

0

[程式新手發問] Python 資料格式問題 (JSON)

各位前輩好, 小弟我第一次發文

最近因公司需要開始學習程式

做資料處理時遇到以下問題:
https://ithelp.ithome.com.tw/upload/images/20200825/20123641IZB7zNWk4o.png

如圖所示, 拿到手上的資料是類似圖1的格式
但是有些地方需要改成圖2那種正常的JSON
開頭與結尾的地方要有[], 每行結束的地方要有,
爬文嘗試用了以下程式碼來執行但卻不如預期

for fn in folder: # 將檔案夾內每個檔案的主檔名與附檔名分開
    file_name = os.path.splitext(fn)
    if file_name[1] == ".json":
        print(file_name[0])
        with open(path+fn) as f: #逐步讀取檔案
            data = f.readlines()
        vl = []
        for i in enumerate(data): #修正 json 格式
            i.replace("}","},")

請問應該如何下程式碼才能從圖1的格式轉換成圖2的格式
還請各位前輩不吝指教, 會給出最佳解答, 感謝 !!

2 個回答

2
listennn08
iT邦高手 7 級 ‧ 2020-08-25 15:05:42
最佳解答
import json

json1 = []
with open(r'D:\\ithelp\20200825.json', 'r') as f:
  for item in f.readlines():
    json1.append(eval(item))
    # json1.append(json.loads(item))
    # 也可以
with open(r'D:\\ithelp\20200825-1.json', 'w') as f:
  f.write(json.dumps(json1))

把資料來源換成你的資料


japhen 大有提到這樣會變字串
可以用 eval 解決
所以更新一下XD

看更多先前的回應...收起先前的回應...
jihong620 iT邦新手 5 級 ‧ 2020-08-25 16:00:28 檢舉

謝謝你, 成功了
另外想請問一下為什麼路徑要用"\"或是"/"

我不太懂你的問題

jihong620 iT邦新手 5 級 ‧ 2020-08-25 16:26:14 檢舉

抱歉剛剛打錯了, 是路徑為什麼都要\\或是/
而不是正常用的\

可以用 \ 不過前要面多加 r 避免被轉譯
\\ 前面不用多加 r
也可以用 / 都是可以的

3
japhenchen
iT邦大師 1 級 ‧ 2020-08-25 16:25:03

樓上大哥的方法會讓原來的Rawdata每行變成字串,輸出會變成

["{.............}","{.............}","{......}"]

比較正確的方法是把讀到的rawdata decode成dict再轉
(個人喜好jsonpickle, 比較不會讓中文看起來怪怪的)

import jsonpickle
import os 
dictdata = list()
if os.path.exists("rawdata.txt"):
    with open('rawdata.txt','r') as rf :
        data= rf.readlines()
    for line in data:
        dictdata.append(jsonpickle.decode(line))
    with open('jsondata.json',"w") as wf:
        wf.writelines(jsonpickle.encode(dictdata))

https://ithelp.ithome.com.tw/upload/images/20200825/20117954GBACd323sl.jpg

https://ithelp.ithome.com.tw/upload/images/20200825/20117954pigFBgzRhn.jpg

看更多先前的回應...收起先前的回應...

我不是大哥/images/emoticon/emoticon16.gif
又多學到一招了 不然每次轉中文都變 utf-8/images/emoticon/emoticon32.gif

eval 好像也會怪怪的,因為rawdata的{ }跟{ }之間沒有逗點,前後也沒有[ ]

jihong620 iT邦新手 5 級 ‧ 2020-08-25 16:58:56 檢舉

感謝兩位 幫大忙了 ~~

我 rawdata 是一行一行轉
所以是字串轉成 dict 加到陣列裡面
以這個資料來說 這樣轉出來是正常的 XD

咳...一行一行eval沒問題啦,只是個人真的不喜歡eval而已....:P

froce iT邦大師 1 級 ‧ 2020-08-26 08:42:03 檢舉

eval得確保你的資料來源是正常可信任的...
要不然我data插段python code到時候你資料庫怎麼死的都不知道。
尤其python又有script語言的特性...

我是沒測試啦,不過我記得readline應該會連換行都讀進去,或許額外需要處理。

就早期的javascript的eval出過大災難,任意內容都能被eval,誰知道裡面是1+1?還是format("C:") ....... (大誤)

所以我就不喜歡eval 了

jihong620 iT邦新手 5 級 ‧ 2020-08-26 09:52:03 檢舉

前輩再次打擾了, 你的方法我很喜歡
抱歉圖片有點多,今天在使用的時候發生了以下問題

import jsonpickle
import os 

path = 'D/0721DATA/'
dictdata = list()
if os.path.exists("2020072119.json"):
    with open('D:/0721DATA/2020072119.json','r') as rf :
        data= rf.readlines()
    for line in data:
        dictdata.append(jsonpickle.decode(line))
    with open('D:/0721DATA/2020072119_1.json',"w") as wf:
        wf.writelines(jsonpickle.encode(dictdata))
else:
    print("檔案不存在,請檢查路徑")

https://ithelp.ithome.com.tw/upload/images/20200826/20123641wjmtOv5wzo.png
回去 rawdata 檢查發現應該是有空行的問題, 如下圖
https://ithelp.ithome.com.tw/upload/images/20200826/201236415LZOak7584.png
只能讀取空行前的資料, 如下圖

import pandas as pd
df = pd.DataFrame(dictdata)
df

https://ithelp.ithome.com.tw/upload/images/20200826/20123641sPfBqsZduj.png

請問前輩在原始資料有這種空行應該要如何解決
是使用 replace 方法將空行取代掉或是有什麼讀取方法呢?

簡單一點

for line in data:
        if line.strip() != '' :
            dictdata.append(jsonpickle.decode(line))
jihong620 iT邦新手 5 級 ‧ 2020-08-26 10:42:55 檢舉

非常感謝 japhenchen 前輩的幫忙
程式碼順利的完成了 !!

標準一點,麻煩一點,用 re (正則表達式) 檢查語法是否符合dictionary的結構

多一個 import re

import jsonpickle
import os 
import re  # 正則表達式函式

reDict = re.compile(r'^{([\'\"][^\"^\']+[\'\"]:[\'\"][^\"^\']+[\'\"],*)+}$',re.IGNORECASE)

# 上面我自幹的pattern可以暫時別看懂,我承認正則真的很繞口,但!!!一定要學紮實,這是蹲馬步!用來檢查是否為合法的dictionary字串


path = 'D/0721DATA/'
dictdata = list()
if os.path.exists("2020072119.json"):
    with open('D:/0721DATA/2020072119.json','r') as rf :
        data= rf.readlines()
    for line in data:
        if reDict.match(line.strip()): # 避開空行或不合規則
            dictdata.append(jsonpickle.decode(line))
    with open('D:/0721DATA/2020072119_1.json',"w") as wf:
        wf.writelines(jsonpickle.encode(dictdata))
else:
    print("檔案不存在,請檢查路徑")
jihong620 iT邦新手 5 級 ‧ 2020-08-26 11:05:08 檢舉

好的, 我再研究看看
謝謝您的補充

froce iT邦大師 1 級 ‧ 2020-08-27 08:06:25 檢舉

不用這麼麻煩吧...
readlines() -> replace("\n", "") -> ",".join() -> 前後加上[] -> json.loads()

下次這種東西最好附測試data。

樓主也說了,中間出現空白行(或許會是有東西不合規則行)

直接load進來或許可能出現無法預期的現象...

CASE BY CASE來寫會比較合乎現況吧

在json的世界裡是允許\n的存在,不用replace也沒關係,不過我還是傾向於逐行檢查再逐行加入新陣列再存檔,因為不可預期的狀況一旦發生,邊際效應下,程式真的難保轉出的資料一定正確(或許可能中途就報錯了)

jihong620 iT邦新手 5 級 ‧ 2020-08-27 08:44:02 檢舉

我的 rawdata 是加速規輸出的資料,檔案很大沒辦法附上
前幾天檢查才發現 rawdata 內會有隔 3 萬筆就出現空行的情形..

依 japhenchen 前輩的方法還蠻順利的,可能資料量大的關係讀取時間稍長(一份 raw data 有 200 萬筆資料),感謝大家的幫忙,初學資料處理,日後有新的問題再請教各位前輩了

我要發表回答

立即登入回答