エンコーディングの黙示録:UTF-8がUTF-8でないとき
私が目撃した最悪のデータの惨事は、2017年に多国籍小売チェーンで発生しました。彼らは12か国の47の地域データベースから顧客データを単一のデータウェアハウスに統合していました。簡単な作業のはずですよね?CSVにエクスポートし、ウェアハウスにインポートし、重複排除ロジックを実行すれば完了です。 しかし、フランス部門のCSVは名前を壊し続けました。「François」は「François」に。「Chloé」は「Chloé」に。ドイツ部門もウムラウトに関して同様の問題を抱えていました。日本部門のデータは完全に読めない状態で、ただの「?」と置き換え文字の行でした。 根本的な原因は?各地域チームが異なるエンコーディングを使用してCSVをエクスポートしていたことでした。フランスはISO-8859-1(Latin-1)を使用し、ドイツはWindows-1252を使用しました。日本はShift-JISを利用し、イギリスとアメリカのチームはUTF-8を使用しましたが、一部はBOM(バイトオーダーマーク)付きのUTF-8で、他はBOMなしでした。スペインのあるチームは、どうにかしてデータをUTF-16LEでエクスポートしてしまっていました。 3ヶ月のスコープで始まった統合プロジェクトは、11ヶ月かかりました。私たちは次のことを行うカスタムエンコーディング検出パイプラインを構築しなければなりませんでした: 1. 複数のライブラリ(chardet、charset-normalizer、およびカスタムヒューリスティック)を使用してエンコーディングを検出しようとします。 2. 各言語で一般的な文字パターンを確認することで検出を検証します。 3. BOMなしのUTF-8にすべて変換します。 4. 手動レビューのために自信度スコアとともにすべての変換をログに記録します。 このパイプラインがあっても、手動修正が必要な3%のエラー率がありました。これは4700万件の顧客記録の3%、つまり人間のレビューが必要な140万件の名前です。 教訓は?CSVのエンコーディングを信頼してはいけません。決して。誰かが「絶対にUTF-8だ」と言っても、確認してください。メタデータでUTF-8と主張しているファイルを見たことがありますが、実際には高ASCII文字を含むWindows-1252でした。ランダムなISO-8859-1のチャンクを持つUTF-8ファイルも見たことがあります。他のシステムからコピー&ペーストされたものです。エクスポートスクリプトがクラッシュし、異なるロケール設定で再起動したためにエンコーディングが途中で切り替わったファイルも見たことがあります。 今、私のデスクを通過するすべてのCSVは、データを見る前にエンコーディング検証スクリプトを通過します。これにより、無数の時間が節約され、少なくとも十件以上の重大なインシデントを防ぎました。存在しなかったホワイトスペース(でも実際にはあった)
2018年、私は6ヶ月間失敗していた財務調整システムを修正するために呼び寄せられました。その会社は何十億ドルもの取引を扱う決済処理業者でした。彼らの調整プロセスは、データベースの取引記録を銀行パートナーからのCSVレポートと比較しました。このシステムは毎日数千件の不一致を報告していました—銀行のレポートに現れる取引がデータベースには存在しなかったり、その逆だったりしました。 財務チームは手動でこれらの不一致を調整しており、60時間の週で追いついていました。彼らはフラグが付けられた各取引を確認して、実際には両方のシステムに存在することを見つけていました。取引IDは完璧に一致していました。しかし、自動システムはそれらを不一致としてフラグ付けし続けていました。 私はコード、データベースクエリ、およびCSVの解析ロジックを2日間分析しました。すべてが正しく見えました。その後、最初から明らかであるべきことをしました:CSVを16進エディタで開きました。 そこにありました。銀行のCSVファイルの各取引IDには末尾にスペースがありました。Excelでは見えませんでした。ほとんどのテキストエディタでも見えませんでした。しかし、16進ダンプでは:`54 52 41 4E 53 31 32 33 34 35 20`ではなく、`54 52 41 4E 53 31 32 33 34 35`になっていました。最後の`20`はスペース文字でした。 データベースは末尾のスペースなしで取引IDを保存していました。比較ロジックは正確な文字列マッチを行っていました。「TRANS12345」≠「TRANS12345 」です。数千件の誤った不一致、数百時間の無駄が、単一の末尾のスペース文字のせいで発生しました。 しかし、ここからがさらに悪化します:末尾のスペースは一貫していませんでした。一部の取引IDには末尾にスペースがあり、一部にはありませんでした。一部には末尾と先頭のスペースがあり、一部には両方があり、いくつかはスペースの代わりにタブを使用していました。一部の記憶に残るファイルには、スペース、タブ、そして非改行スペース(U+00A0)が混在していました。 修正は単純でした—インポート時にすべてのホワイトスペースをトリムします。しかし、教訓は深刻でした:CSVにおけるホワイトスペースは決して偶然ではなく、常に問題であり、頻繁に見えません。私は今、ルールを持っています:すべての文字列フィールドはインポート時にトリムされ、例外はありません。ビジネスロジックがフィールドにホワイトスペースを保持すべきだと言っても構いません。誰かがデータがクリーンだと主張しても気にしません。すべてをトリムしてください。 他の見えない文字にも注意するように学びました:ゼロ幅スペース(U+200B)、ゼロ幅非結合子(U+200C)、ゼロ幅結合子(U+200D)、およびファイルの途中に現れることがある恐ろしいバイトオーダーマーク(U+FEFF)です。これらの文字は、機械の幽霊であり、人間には見えませんが、コンピュータには非常に現実的です。国際商取引を壊した日付フォーマット
私が経験したことのある、呪われた日付フォーマットについて話しましょう。これは、アジアの製造業者と北アメリカおよびヨーロッパの小売業者の間の出荷を調整する物流会社でのことです。 システムは次のように機能していました:製造業者が出荷の詳細を含むCSVファイルをアップロードします。これにはピックアップ日、推定納品日、税関クリアランス日が含まれていました。システムはこれらの日付を解析し、輸送時間を計算し、運送会社や税関ブローカーと調整しました。 すべては数年間問題なく機能しました。しかし、2016年3月に、システムが過去の日付の出荷をスケジュールし始めました。2016年3月15日にピックアップされるはずのコンテナが、1916年3月15日にスケジュールされていました。税関の書類は、コンテナ輸送の発明以前の日付について提出されていました。 根本的な原因は?Excelの自動日付フォーマットと地域の日付フォーマットの違い、そして日付に関する真に驚くべき誤解が組み合わさった結果です。 以下のように起こっていました: 1. 中国の製造業者が「3/15/2016」(MM/DD/YYYYフォーマットで2016年3月15日)という日付を入力します。 2. Excelはこれを日付として解釈し、内部的にシリアル番号として保存します(2016年3月15日の42444)。 3. CSVにエクスポートされると、Excelはシステムロケールに基づいてフォーマットします。 4. 中国のシステムロケールはYYYY-MM-DD形式を使用したため、「2016-03-15」としてエクスポートされます。 5. 私たちのインポートシステムはMM/DD/YYYY形式に設定されていたため、「2016-03-15」を「2016/03/15」(2016年の3月、15日)として解析します。 6. 2016年の月は無効であるため、パーサーは「20/16/03/15」として解釈しなおします。 7. 次第に絶望的な解析の試行を経て、最終的に「03/15/1916」と落ち着くことになります。 しかし、待ってください、さらに悪化します。一部の製造業者はDD/MM/YYYY形式を使用していました。一部はYYYY-MM-DDを使用しており、一部はMM/DD/YY(二桁の年)を使用していました。台湾のある製造業者は、Minguoカレンダーを使用しており、年105は2016年CE(1912 + 105)に相当します。 私たちは1916年から2116年までの日付を持ち、特に1970年(Unixエポック)を中心に群集が密集していました。これは、一部のシステムがUnixタイムスタンプとして日付をエクスポートし、私たちのパーサーがそれらをYYYYMMDD形式として解釈していたためです。 解決策は次のことを必要としました: - フォーマットを検出しようとするマルチストラテジーの日付パーサーを実装すること - バリデーションルールを追加する(2000年以前または2050年以降の日付を拒否) - 製造業者にISO 8601形式(YYYY-MM-DD)を独占的に使用させる - インポートの前に解析済みの日付をプレビューするCSVアップロードのウェブインターフェイスを構築すること - あらゆる考えうる形式の日付に関する包括的なテストスイートを作成すること これらすべての安全策があっても、時折日付解析エラーが発生します。先月、誰かが「2/29/2023」(2023年2月29日—2023年はうるう年ではないため存在しない日付)を入力したCSVに出くわしました。Excelは喜んで受け入れ、シリアル番号45000として保存し、「2023-02-29」としてエクスポートしました。私たちのシステムはそれをインポートし、正しいフォーマットであることを確認し、存在しない日付のために出荷をスケジュールしました。「日付の問題は、誰もが理解していると思っているが、実際には誰も理解していないということです。日付は数学的なものではなく、文化的な構造物です。時間帯や夏時間、うるう年、うるう秒、カレンダー改革があります。国によってさまざまな形式があり、異なる時代の異なる出発点があり、異なるコンテキストで異なる意味を持ちます。そして、メタデータが完全に欠如しているCSVファイルでは、どの解釈が正しいのか知る方法はありません。」この同僚の引用は、日付の問題を完璧に捉えています。CSVにはデータ型がありません。スキーマもありません。単なるテキストです。CSVに「01/02/03」とあれば、それは2003年1月2日ですか?2003年2月1日ですか?2001年3月2日ですか?2001年2月3日ですか?文脈がなければ知る方法はなく、文脈こそCSVが提供しないものです。
数字ではなかった数字
以下は、私が出会った最も一般的な数値データの問題の表で、それぞれの頻度と典型的な影響を示しています:| 問題の種類 | 頻度 | 典型的な影響 | 例 |
|---|---|---|---|
| 千の区切り | 非常に高い(60%) | インポート失敗、型エラー | 「1,234.56」が文字列として解析される |
| 通貨記号 | 高い(45%) | インポート失敗、計算エラー | 「$1,234.56」または「€1.234,56」 |
| 小数点区切りの違い | 高い(40%) | 破滅的な計算エラー | 「1.234,56」(欧州)対「1,234.56」(米国) |
| 指数表記 | 中程度(25%) | 精度の損失、誤解 | 「1.23E+05」または「1.23456789E-10」 |
| 先頭のゼロ | 中程度(30%) | データ損失、IDの破損 | 「00123」が「123」になる |
| パーセント記号 | 中程度(20%) | 100倍の計算エラー | 「15%」が0.15ではなく15として保存される |
| 負の数形式 | 低い(15%) | 符号損失、不正確な計算 | 「(123) C
Written by the CSV-X Team Our editorial team specializes in data analysis and spreadsheet management. We research, test, and write in-depth guides to help you work smarter with the right tools. Related Tools Related Articles Data Cleaning 101: Fix Messy Data in 10 Steps — csv-x.com Excel Pivot Tables: Beginner to Advanced How to Fix CSV Encoding Issues (UTF-8, Latin-1, and the Dreaded Mojibake)Put this into practice Try Our Free Tools → |