質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

6805閲覧

C++ RapidJSONにて、特定文字がはいったJSONファイルをパースするとエラーが発生します。解決方法をご教授ください。

beginnerCPP

総合スコア1

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/10/01 07:41

VisualStudio2015 C++で、JSONファイルの読込を実装しようとしています。
ライブラリはRapidJSONを使っています。

JSONファイルをパースする所で、エラー「文字列中に無効な文字があります」が発生しましたが、
その理由が分かりません。

試行錯誤した結果、「表」という文字がJSONファイルに含まれているとパースでエラーが発生します。
別の文字であればエラーが発生せずに正常にパースでき、値の取得もできるため、コードのどの部分を修正すればよいか分からず悩んでいます。

C++に対する知識もまだ浅いため、文字によらずパース可能にするためにはどこを改善すべきかご教授頂けますと助かります。
宜しくお願いいたします。

JSONファイル

[

{
"Cd" : "A001",
"Nm" : "裏"
},
{
"Cd" : "A002",
"Nm" : "表"
}
]

コード ※doc.HasParseError();でエラー発生

#include "stdafx.h" #include "rapidjson/document.h" #include "rapidjson/istreamwrapper.h" #include <iostream> #include <fstream> #include <Windows.h> #include <string> using namespace rapidjson; int main() { std::ifstream ifs{ R"(D:\work\TESTJ.json)" }; if (!ifs.is_open()) { //OPENエラー return -1; } IStreamWrapper isw{ ifs }; Document doc; doc.ParseStream(isw); bool error = doc.HasParseError(); if (error) { //Parseエラー return -1; } // string rapidjson::Value& NM = doc; int i, l = NM.Size(); for (i = 0; i < l; i++) { char cVal; std::cerr << NM[SizeType(i)]["Nm"].GetString() << std::endl; } return 0; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yoorwm

2020/10/01 07:47

確か、JSONの規格自体がUTF-8前提とかそういう話だったと思うので、読み込むファイルのエンコーディング調べてみるとどうでしょうか?
beginnerCPP

2020/10/01 07:54

ありがとうございます。 読み込んでいたJSONファイルはSJISでした。 UTF8でJSONファイルを保存して実行するとパースは通るようになりましたが「NM[SizeType(i)]["Nm"].GetString()」の箇所で「陬・」など文字化けして出力されました。 エンコードまわり調べてみたいと思います。
SHOMI

2020/10/01 08:13

「陬・」 それはUTF8の「裏」の文字コードをそのままSJISの文字コードとして表示しようとしたためです。
guest

回答3

0

皆さまありがとうございます!
アドバイスを元にコードを修正しました。
「表」の文字も正常に出力できることを確認できています。

≪改善策≫
・JSONファイルはUTF-8で保存すること。
・Windowsで標準入出力を介して出力する場合、UTF8→ShiftJISの変換が必要。

※変換処理部分のコードは以下のサイトより丸パクり参考にさせて頂きました。。
https://sayahamitt.net/

C++

1#include "stdafx.h" 2 3#include "rapidjson/document.h" 4#include "rapidjson/istreamwrapper.h" 5#include <iostream> 6#include <fstream> 7#include <Windows.h> 8#include <string> 9 10using namespace rapidjson; 11 12std::string UTF8toSjis(std::string srcUTF8) { 13 //Unicodeへ変換後の文字列長取得 14 int lenghtUnicode = MultiByteToWideChar(CP_UTF8, 0, srcUTF8.c_str(), srcUTF8.size() + 1, NULL, 0); 15 16 //必要な分だけUnicode文字列のバッファ確保 17 wchar_t* bufUnicode = new wchar_t[lenghtUnicode]; 18 19 //UTF8→Unicodeへ変換 20 MultiByteToWideChar(CP_UTF8, 0, srcUTF8.c_str(), srcUTF8.size() + 1, bufUnicode, lenghtUnicode); 21 22 //ShiftJISへ変換後の文字列長取得 23 int lengthSJis = WideCharToMultiByte(CP_THREAD_ACP, 0, bufUnicode, -1, NULL, 0, NULL, NULL); 24 25 //必要な分だけShiftJIS文字列のバッファ確保 26 char* bufShiftJis = new char[lengthSJis]; 27 28 //Unicode→ShiftJISへ変換 29 WideCharToMultiByte(CP_THREAD_ACP, 0, bufUnicode, lenghtUnicode + 1, bufShiftJis, lengthSJis, NULL, NULL); 30 31 std::string strSJis(bufShiftJis); 32 33 delete bufUnicode; 34 delete bufShiftJis; 35 36 return strSJis; 37} 38 39int main() 40{ 41 std::ifstream ifs{ R"(D:\work\TESTJ.json)" }; 42 if (!ifs.is_open()) 43 { 44 //OPENエラー 45 return -1; 46 } 47 48 IStreamWrapper isw{ ifs }; 49 50 Document doc; 51 doc.ParseStream(isw); 52 53 bool error = doc.HasParseError(); 54 if (error) { 55 //Parseエラー 56 return -1; 57 } 58 59 // string 60 61 rapidjson::Value& NM = doc; 62 int i, l = NM.Size(); 63 for (i = 0; i < l; i++) { 64 char cVal; 65         //SJISに変換して出力 66 std::cerr << UTF8toSjis(NM[SizeType(i)]["Nm"].GetString()) << std::endl; 67 } 68 69 return 0; 70} 71 72

投稿2020/10/01 09:56

beginnerCPP

総合スコア1

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

そのとき JSON はどのような文字コードで保存しましたか?

CP932 (Shift_JIS) における「表」は 95 5c で表され、 5c は文字 \ に対応します。 JSON では \ はエスケープのための文字として解釈しますから、まともに解釈できなくなるということが考えられます。

いわゆる「ダメ文字」と呼ばれるものです。


余談ですが、 JSON の仕様は元々は文字コードに関する指定はなく、アプリケーションの裁量でやることになっていました。 現時点の最新仕様では UTF-8 であることが必須になっているので多くのパーサは UTF-8 を前提としますけども、一部のパーサはいくつかの文字コードをサポートしていたり、デフォルトでは ASCII の範囲しか認めないものもあるなどして若干の混乱があります。

RapidJSON の場合は UTF-8, UTF-16, UTF-32 をサポートしているようです。

投稿2020/10/01 07:57

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

beginnerCPP

2020/10/01 08:36

ありがとうございます。 JSONファイルはSJISで保存していました。 UTF8でJSONファイルを保存しなおして実行するとパースは通るようになりましたが「NM[SizeType(i)]["Nm"].GetString()」の箇所で「陬・」など文字化けして出力されました。 文字コード部分がよくわかっておらず、「NM[SizeType(i)]["Nm"].GetString()」の記述を変えればうまくいくのかなと思い模索しています。
SaitoAtsushi

2020/10/01 08:58

いいえ。 それは正しく文字列を取得できています。 UTF-8 の文字列を CP932 として解釈するとその文字列になります。 Windows では標準入出力を介してターミナルへ出力しようとすると (使用言語の設定が日本語になっているなら) CP932 と解釈することになっているので UTF-8 をそのまま表示することが出来ません。
beginnerCPP

2020/10/01 09:28

つまり、UTF8→SJISへの文字コード変換をかけてから出力すれば文字化けせずに正しく「表」の文字を認識できるということですね。 ありがとうございます!解決できそうです!
SaitoAtsushi

2020/10/01 10:00

はい。 ただし、 Unicode (UTF-8) にあって SJIS (CP932) にはない文字というのはたくさんありますから、変換をかけるというのが妥当な処理方法なのかは場合によると思います。 「『標準入出力を介して』ターミナルへ出力しようとする場合」には CP932 と解釈されるということであって、ターミナルそのものは Unicode に対応しています。 WriteConsole API を使って表示すれば Unicode を表示可能です。 ただし、 Windows API がいうところの Unicode は UTF-16 のことです。 どうせ変換をかけるのであれば CP932 に変換するよりも UTF-16 に変換する方が処理コストは小さいはずです。
guest

0

「表」という文字がJSONファイルに含まれているとパースでエラーが発生します。

文字コードがShiftJISではないでしょうか。
ShiftJISで「表」の2バイト目は\なのでエスケープされていない\が現れてエラーとなったのでしょう。
文字コードをUTF8に変換できませんか?

投稿2020/10/01 07:51

SHOMI

総合スコア4079

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

beginnerCPP

2020/10/01 08:04

ありがとうございます。 ありがとうございます。 ご指摘の通り、読み込んでいたJSONファイルはSJISでした。 UTF8でJSONファイルを保存し直してから、コードを実行するとパースは通るようになりましたが「NM[SizeType(i)]["Nm"].GetString()」の箇所で「陬・」など文字化けして出力されました。 ファイルの読み込み部分から変更する必要があるのでしょうか。エンコード部分調べてみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問