曲線引用符がコード・JSON・CSVを壊す理由

一見まったく問題ない行をエラーが指し示すのは、その違いが見た目では分からないからです。

曲線引用符(“ ” ‘ ’)は、プログラミング言語やデータ形式が要求する直線引用符(" ')とは別のUnicode文字です。パーサーはコードポイントを厳密に照合するため、曲線引用符は単なる普通の文字として扱われ、文字列が開始されません。直線引用符に置き換えればすぐに解決します。

実際に別の文字である

問題の全体像は、この1つの表に集約されます。

文字 名前 コードポイント
" 直線二重引用符 U+0022
左二重引用符 U+201C
右二重引用符 U+201D
' 直線アポストロフィ U+0027
左単一引用符 U+2018
右単一引用符 U+2019

プログラミング言語、JSON、CSV、シェルインタプリタが文字列の区切りとして認識するのは、このうちU+0022とU+0027の2つだけです。残りの4つは、文字やカンマと同じ区分の、ごく普通の表示可能な文字です。

つまり、パーサーが“name”に出合ったとき、少し装飾的な引用符で囲まれた文字列としては見えません。予期しない記号で始まる、引用符なしの文字列として見えるのです。エラーメッセージはunexpected tokenのような内容で、まったく正しく見える行を指し示します。通常のフォントサイズでは、"と“の違いはわずか数ピクセルの曲がり具合に過ぎないからです。

チャットから貼付{ name: Ada }SyntaxError: Unexpected token '“'正規化後{ "name": "Ada" }
曲線引用符は、パーサーが想定する直線引用符とは別の文字です。

どこから紛れ込むのか

ほとんどの場合、ソフトウェアの「親切な機能」が原因です。

  • WordとGoogle Docsは、入力中に直線引用符を曲線引用符へ自動変換します。デフォルトで有効になっており、文章としては望ましい動作なので、ほとんどの人は気づきません。
  • チャットモデルは、正式な引用符で組版された出版物の文章から学習しているため、曲線引用符を生成します。
  • macOSは、多くのテキストフィールドでスマート置換をシステム全体に適用します。
  • CMSのエディターやコメント欄は、投稿された文章にタイポグラフィのフィルターをかけることがよくあります。
  • PDFからのコピー&ペーストは、組版時に使われた文字をそのまま持ち込みます。プロが制作した文書であれば、それは曲線引用符です。

共通しているのは、「解析するためのもの」に渡る途中で、「読むためのもの」を通過しているという点です。文章にはタイポグラフィの引用符が適し、コードには正確なバイト列が必要です。この境界で問題が起きます。

同様の仲間も知っておく価値があります。3つのピリオドの代わりの省略記号(…)、ハイフンの代わりのエン・エムダッシュ、通常のスペースの代わりのノーブレークスペースです。どれも似ているASCII文字とは別のコードポイントであり、同じように気づかれない形でパーサーを壊します。

具体的に何が壊れるのか

JSON。 JSONの文字列はすべてU+0022で囲む必要があります。曲線引用符が1つあるだけで文書全体が無効になり、パーサーは最初の失敗箇所しか報告しないため、数十か所あるファイルを手作業で直すには何度もやり直しが必要です。JSON整形・検証ツールに貼り付ければ、最初の問題箇所の正確な位置が分かります。

CSV。 引用符のルールは、カンマを含むフィールドを保護するためにあります。曲線引用符は引用符として認識されないため、“Smith, John”のようなフィールドはカンマで分割され、それ以降の列がすべて1つずつずれます。これは構文エラーより厄介で、警告なく失敗します。何事もなくインポートできてしまうのに、内容が間違ったファイルができ上がるのです。

ソースコード。 多くの言語ではコンパイルエラーかパースエラーになるので、少なくとも問題には気づけます。シェルスクリプトではさらに悪い事態になりえます。ハイフンの代わりにエンダッシュを使ったrm –rfは意図したフラグではなく、曲線引用符で囲んだ引数はリテラル文字列としてそのまま渡されます。

設定ファイル。 YAML、TOML、.envファイルは、曲線引用符を値の一部として黙って受け入れます。APIキーに装飾文字がくっつき、認証が失敗しても、ログには理由が何も表示されません。

正規表現と検索。 直線引用符を含むパターンは曲線引用符を含むテキストにマッチしないため、検索・置換が静かに0件を返します。

正しい直し方

テキストを正規化する。 曲線引用符を直線引用符に変換に貼り付けると、4種類の曲線引用符をすべてASCII相当の文字に置き換え、置き換えた数を表示します。AIが生成した文章なら、ChatGPT・AI文章クリーナーで引用符だけでなく、エムダッシュや不可視文字、絵文字も一度に処理できます。

発生元を止める。 繰り返し起きる場合は、自動変換を無効にしましょう。

  • Word:ファイル → オプション → 文章校正 → オートコレクトのオプション → 入力オートフォーマット → 「直線引用符を曲線引用符に変換する」のチェックを外す。
  • Google Docs:ツール → 設定 → 「スマート引用符を使用する」のチェックを外す。
  • macOS:システム設定 → キーボード → テキスト入力 → 編集 → スマート引用符とダッシュをオフにする。

コードをワープロで書かない。 根本的な解決は構造的なものです。パーサーに渡すものはプレーンテキストエディターで書きましょう。文字が勝手に書き換えられることはありません。

直しすぎに注意する。 文章に含まれる曲線引用符まで一律に置き換えてはいけません。記事やメールではタイポグラフィの引用符が正しく、直線引用符のほうが見た目が悪くなります。正規化は、文書からコードやデータへ移る境界でだけ行うのが原則です。

引用符を正規化してもまだ失敗する場合、次の容疑者は不可視文字です。不可視Unicode文字のリファレンスを参照してください。

よくある質問

見た目は正しいのにJSONがunexpected tokenと言うのはなぜですか?

ほとんどの場合、直線引用符であるべき場所に曲線引用符が混ざっています。JSONはU+0022のみを要求し、曲線引用符のU+201CとU+201Dはパーサーにとって普通の文字です。画面上の違いは数ピクセルしかないため、その行は正しく見えてしまいます。

曲線引用符と直線引用符の違いは何ですか?

別のUnicode文字です。直線引用符はU+0022とU+0027で、あらゆるパーサーが期待するASCII文字です。曲線引用符はU+2018、U+2019、U+201C、U+201Dで、文字に向かってカーブするタイポグラフィの記号です。文章では正しいですが、文字列の区切りとしては無効です。

曲線引用符を直線引用符に変換するには?

「曲線引用符を直線引用符に変換」などの正規化ツールにテキストを貼り付けると、4種類すべてを置き換えて件数を表示します。検索・置換でやると文字ごとに4回の操作が必要になり、途中で漏れが出やすいのが難点です。

CSVをインポートすると列がずれるのはなぜですか?

カンマを含むフィールドが保護されるのは、直線引用符で囲まれている場合だけです。曲線引用符は引用符として認識されないため、フィールドがカンマで分割され、それ以降の列がすべてずれます。警告なく失敗するため、正常にインポートできたのに内容が間違ったファイルになります。

曲線引用符は常に削除すべきですか?

いいえ。文章の中では正しいタイポグラフィであり、直線引用符より見た目も優れています。正規化が必要なのは、テキストがコード、JSON、CSV、設定ファイルなど、読むためではなく解析される対象に渡るときだけです。

このガイドで紹介しているツール

関連ガイド