Rails JSON::ParserError 問題


#1

各位好 小弟想問一個怪怪的問題了!

最近在做個應用,須解析以下的 json資料
json 資料來源 -高市政府資料開放平台

小弟使用 gem httparty 來實現它

url = '上面的json網址'
response = HTTParty.get(url)
puts JSON.parse(response.body)

它就出現了 JSON::ParserError
28

而我在 irb 下測試

url = '上面的json網址'
response = HTTParty.get(url)
puts JSON.parse(response.body)

是好的!沒有error,想請問這到底是啥問題吶? 毫無頭緒…


#2

首先 … "看得到"和"實際編碼"一直都是兩回事,這在編碼問題上都是首要重點,類似傳統的『許蓋功』問題一樣

如果東西看不到呢?來做個測試唄 …

require 'open-uri' #對方沒有過濾,用最簡單的 open-uri 來當 http client
require 'json'
url = 'https://data.kcg.gov.tw/dataset/a98754a3-3446-4c9a-abfc-58dc49f2158c/resource/48d4dfc4-a4b2-44a5-bdec-70f9558cd25d/download/cusersjackodesktop1070316opendatajson-1070316.json'
body = open(url).read.force_encoding('UTF-8') #預設可能丟 ASCII-8BIT 這邊轉回 UTF-8

#直接 JSON.parse 會噴,所以下面來過濾 ...

char_set = body.scan(/./).uniq.sort #印出所有使用的文字,並排序列出
#這邊你可以看到最後一個"字"怪怪的,沒東西,但又不是空白(ASCII 都在最前面才是)
wrong_char = char_set[-1]
wrong_char.ord #取得文字編碼(Base 10 : 65279)
wrong_char.ord.to_s(16) #取得文字編碼(Base 16 : FEFF)

之後找這種網站

取得解答 … 零寬空白,基本上當 UTF-8 來用而非空白,類似中文字但沒寬度看不到
再來尋找和排除即可 …

body.index(wrong_char) # index 0 ..... 所以第一個字元就是了 ... 找不到應該是 nil
JSON.parse(body[1..-1]) #即為所求

以上


#3

Wow ~ 解決哩!

看來編碼問題與怎麼排除在解析文件裡都是一項蠻大的課題!
寫完JC大你的程式碼後,讓我了解面對一份看起來幾乎沒問題的json文件,若直接轉譯有錯的話

是先要檢查它的編碼或字元是否有問題!

先前我沒想到可以從這個地方下手,而一直在找是不是還有其它解析 json 的方法~
恩~ 這次我了解了,感謝大大~ 問題成功解決!

另尋問若 body 文件中,存在多個 要排除的字元這邊是否要變成用取代或其它方式?

body.index(wrong_char) 
JSON.parse(body[1..-1])

#4

基本上是,你可以用很多手法過濾掉該字元,不過最簡單還是"先看到"會比較好,也就是上面我用的列表的方式(當然你也可以過濾文字編碼範圍做信任區域之類的,CJK 應該都有大概的 range 才是)

至於其餘的要過濾的話,會類似

wrong_char = 0xFEFF.chr(Encoding::UTF_8) #你可以得到原字,尤其此字"無法輸入"時
body = body.gsub(wrong_char , '') #單純清除

大概就這樣而已唄,不過這題我說不定不會過 JSON.parse 唄哈哈,因為很多時候很鬼,而是直接

body.scan(/"([^"]+)"/).map{|i|i[0]}.each_slice(2).each_slice(4).map{|i|i.to_h}
#scan 把文字裁出,map濾掉空array,兩個包一個array,四個包一組,把單組資料變成 hash

看不懂的話可以先玩這個,類似

{wer:123 , sdf:234}.to_a.to_h # each_slice 沒過 block 的話效果和 to_a 差不多就是

不過這邊都是包裝手法應用罷了,你可以選擇自己想要的包裝方式才是,自己玩看看?


#5

恩恩,了解哩! 我再去玩玩看嘍~ 感恩~~~!!!


#6

看到莫明這三個字 的噴笑出來,專業專業