「10時~12時」の「~」が「?」になるのは、文字コードの変換に「Shift_JIS」を使っているためです。 Windows で使われている日本語の文字コードは、正確には Windows-31J(MS932・cp932) という Shift_JIS の拡張で、「~」などいくつかの文字は、Shift_JIS と Unicode への対応のしかた(変換表)が違います。

直し方は、Shift_JIS と書いている所を Windows-31J(cp932)にすることです。

言語・ソフト 「Shift_JIS」の代わりに使う名前
Java windows-31j(別名 MS932)
Python cp932
MySQL cp932(sjis ではなく)
HTML・メールの宣言など 相手のシステムの仕様に合わせる(下で説明)

確認環境:Java 21、Python 3.11、MySQL 8.0.46(確認日 2026年10月11日)。同じ文字を Shift_JIS と Windows-31J(cp932)で変換して比べました。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「「~」が「?」になる原因と直し方|波ダッシュ問題」

再現:「~」を Shift_JIS に変換すると「?」になる

String input = "10時~12時";
System.out.println(new String(input.getBytes("Shift_JIS"), "Shift_JIS"));
// 10時?12時                  ← 「~」が ? になった

System.out.println(new String(input.getBytes("windows-31j"), "windows-31j"));
// 10時~12時                 ← 正しく戻る

Python では、? にならずにエラーになりました。

>>> "10時~12時".encode("shift_jis")
UnicodeEncodeError: 'shift_jis' codec can't encode character '~' in position 3: illegal multibyte sequence
>>> "10時~12時".encode("cp932")
b'10\x8e\x9e\x81\x6012\x8e\x9e'

Java は黙って ?(0x3F)に置き換え、Python はエラーで止まります。 Java のほうが気づきにくく、CSV や帳票に ? が出て初めて分かります。

なぜ起きるのか:同じ「0x8160」が、別の文字に対応している

Shift_JIS の 0x8160 は「~」の形の文字です。この 0x8160 を Unicode のどの文字に対応させるかが、2つの文字コードで違います。

0x8160 を読むと Unicode の文字
Shift_JIS として読む U+301C(WAVE DASH「〜」)
Windows-31J(cp932) として読む U+FF5E(FULLWIDTH TILDE「~」)

Windows で入力・保存された「~」は、Windows-31J の変換表では U+FF5E です。これを Shift_JIS に変換しようとしても、Shift_JIS の変換表には U+FF5E が無いため、「?」になります。見た目はほとんど同じ別の文字なので、画面では区別がつきません。MySQL 公式マニュアルの sjis と cp932 の変換表でも、同じ違いが示されています。

化ける文字の対応表

Java で変換した結果です(3F は「?」に置き換えられたことを示します)。

文字(Unicode) Shift_JIS Windows-31J
~ U+FF5E(全角チルダ) 3F 8160
〜 U+301C(波ダッシュ) 8160 3F
- U+FF0D(全角ハイフンマイナス) 3F 817C
− U+2212(マイナス) 817C 3F
∥ U+2225(平行) 3F 8161
‖ U+2016(二重縦線) 8161 3F
― U+2015(水平線) 3F 815C
¢ U+FFE0(全角セント) 3F 8191
¬ U+FFE2(全角否定) 3F 81CA
① U+2460(丸数字) 3F 8740
㈱ U+3231 3F 878A
髙 U+9AD9(はしごだか) 3F FBFC
文字の種類 何が起きるか
~ - ∥ ― ¢ £ ¬ 変換表の違い。Windows で入力したものは Shift_JIS で ?
① ㈱ 髙 などの機種依存文字 Shift_JIS にはそもそも無い。Windows-31J にはある

丸数字・㈱・はしごだかも、Shift_JIS では「?」になります。Windows で作られたデータを扱うなら、Windows-31J を使うのが基本です。

言語によって、変換表が少しずつ違う

Python の cp932 と Java の windows-31j で、同じ文字を比べると、結果が違うものがありました。

文字 Java windows-31j Python cp932
〜 U+301C(波ダッシュ) 3F(?) 8160(~ と同じ値に変換)
髙 U+9AD9 FBFC EEE0
― U+2015 815C 815C
— U+2014(EM DASH) 3F エラー

Java の Windows-31J は「〜」(U+301C)を ? にしますが、Python の cp932 は 0x8160 に変換しました。 U+301C の「〜」を含むデータ(ほかのシステムから来たものなど)を Java で Windows-31J に変換すると、? になります。複数の言語・システムをまたぐなら、変換の前に、文字をそろえる処理を入れます(下の直し方3)。

ありがちな場面:Excel の CSV を Shift_JIS で読む

byte[] fromExcel = "10時~12時".getBytes("windows-31j");   // Excel が保存した CSV
String read = new String(fromExcel, "Shift_JIS");          // Shift_JIS で読む
// read = "10時〜12時"(U+301C)  equals("10時~12時") → false

? にはならず、見た目も同じなのに、文字が U+301C に変わっていました。 この文字列を DB に保存して、画面(Windows)から「~」で検索すると、一致しません。読むときも書くときも Windows-31J を使います。

new String(fromExcel, "windows-31j").equals("10時~12時")   // true

直し方

1. 文字コードの名前を Windows-31J・cp932 にする

言語・ライブラリ 書き方
Java(文字列・入出力) "windows-31j" または "MS932"(同じもの)
Java(Charset) Charset.forName("windows-31j")
Python open(path, encoding="cp932")、s.encode("cp932")
MySQL の列・テーブル CHARACTER SET cp932

Java では MS932 は windows-31j の別名です(確認環境でも Charset.forName("MS932").name() は windows-31j)。SJIS は Shift_JIS の別名なので、SJIS と書いている所も直します。

2. MySQL は sjis ではなく cp932

(sjis の列に「10時~12時」を INSERT)
ERROR 1366 (HY000): Incorrect string value: '\xEF\xBD\x9E12\xE6...' for column 's_sjis' at row 1

(cp932 の列)
10時~12時   31308E9E816031328E9E     ← 保存できた

sjis の列には、Windows の「~」(U+FF5E)を保存できませんでした。 同じ 0x8160 として保存されたデータでも、sjis の列から読むと「〜」(U+301C)、cp932 の列から読むと「~」(U+FF5E)になりました。新しく作るなら、文字コードの問題がない utf8mb4 にするのが一番です(関連記事の「Incorrect string value」で解説)。

3. 変換する前に、文字をそろえる

ほかのシステムから来たデータに、U+301C の「〜」やマイナス記号が混ざる場合は、Windows-31J に変換する前に置き換えます。

static String toWindows31jSafe(String s) {
    return s.replace('〜', '~')   // 〜 → ~
            .replace('−', '-')   // − → -
            .replace('‖', '∥')   // ‖ → ∥
            .replace('¢', '¢')   // ¢ → ¢
            .replace('¬', '¬');  // ¬ → ¬
}

Unicode の正規化(NFKC)を使う方法もありますが、確認環境では NFKC で「~」(U+FF5E)は半角の ~ に変わり、「〜」(U+301C)は変わりませんでした。見た目を保ったまま置き換えたいなら、上のように明示的に置き換えます。

4. 相手のシステムが「Shift_JIS」を指定している場合

取引先のシステムや帳票の仕様で「Shift_JIS」と指定されていても、実際には Windows-31J のことが多いです。「~」や丸数字を送ってよいか、相手に確認します。本当に Shift_JIS(JIS X 0208 の範囲だけ)なら、送る前に機種依存文字を置き換えるか、エラーにします。

確認の手順(チェックリスト)

順番 確認すること 方法
1 化ける文字 ~ - ∥ ― ¢ ¬、① ㈱ 髙 か
2 文字コードの指定 Shift_JIS・SJIS・sjis と書いている所を探す
3 読む側・書く側の両方 読むときも書くときも windows-31j・cp932
4 DB MySQL の列が sjis なら cp932(できれば utf8mb4)
5 ほかのシステムから来たデータ U+301C・U+2212 などを置き換えてから変換
6 検索で一致しない 文字のコード(U+FF5E か U+301C か)を確かめる

よくある質問

Q. 文字のコード(U+FF5E か U+301C か)は、どう確かめますか。 A. Java なら Integer.toHexString(s.charAt(i))、Python なら hex(ord(c)) です。MySQL なら HEX() で保存されたバイトを確かめます。

Q. UTF-8 にすれば起きませんか。 A. UTF-8 どうしなら起きません。Shift_JIS・Windows-31J との変換が入る所(Excel の CSV、以前からのシステムとの連携、帳票)で起きるので、その変換の箇所で Windows-31J を使います。

まとめ

  • 「Shift_JIS」で変換すると、Windows の「~」(U+FF5E)は「?」になる
  • 原因は変換表の違い。0x8160 は Shift_JIS では U+301C、Windows-31J では U+FF5E
  • - ∥ ― ¢ ¬、① ㈱ 髙 も同じく化ける
  • 直し方は Java は windows-31j、Python は cp932、MySQL は cp932(できれば utf8mb4)
  • Shift_JIS で読むと、? にならずに U+301C に変わり、検索で一致しなくなる
  • Java は黙って ?、Python はエラー。言語によって変換表も少し違う

参考・出典

確認日はいずれも 2026年10月11日です。

  • MySQL 8.0 Reference Manual「The cp932 Character Set」:https://dev.mysql.com/doc/refman/8.0/en/charset-cp932.html
  • Java SE 21「Supported Encodings」:https://docs.oracle.com/en/java/javase/21/intl/supported-encodings.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「「~」が「?」になる原因と直し方|波ダッシュ問題」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?