🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

1821閲覧

Java 8で文字化けした文字を扱うとNullPointerExceptionになる (無効な文字を除去したい)

beyond_the_avg

総合スコア6

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2019/11/02 00:05

WebサイトのクローラーでWebページを集めたファイルがあります。このクローラーは問題があり、全てのページがUTF-8であることが前提となっています(改修する予定です)。

例えば2つのWebサイトをクロールしたとします。

  • WebサイトA - EUC-JPでエンコードされている
  • WebサイトB - UTF-8でエンコードされている

これを1つのテキストファイルに押し込んだ結果、サイトAのテキストが全部文字化けした1つのテキストファイルができました(このバグは直しますが既に集めたデータは壊れています)。このファイルはJSONになっていて、1行に1つのサイトのデータが入っています。

ここで

java

1char [] array = in.toCharArray(); 2StringBuilder sb = new StringBuilder(); 3 4for( char ch : array ) 5{ 6 boolean condition1 = Character.UnicodeBlock.of(ch).equals(CJK_UNIFIED_IDEOGRAPHS); 7 boolean condition2 = Character.UnicodeBlock.of(ch).equals(BASIC_LATIN); 8// boolean condition3 = Character.UnicodeBlock.of(ch).equals(CJK_COMPATIBILITY_IDEOGRAPHS); 9 10 if( condition1 || condition2 ) 11 { 12 sb.append(ch); 13 } 14 else 15 { 16 // この文字は使わない 17 } 18

のようなコードを書いています。意図するものはCJKかBASIC_LATINに属する文字の場合だけ残すことです。あとひらがな、カタカナも許可しますがここでは割愛します。

このコードで文字化けした行を読むと、condition1のところでchはNULLではないはずですが、NullPointerExceptionになります。

質問

  • 同じ内容のRubyコードでは止まらずに処理できます(速度面でJavaで行いたい)
  • arrayは文字の配列のはずが、nullが含まれることがあるように見える
  • これを回避する方法はありませんか?
  • JDKのバグだとしたら、その報告は出ていませんか? NullPointerExceptionは一般的過ぎて検索で絞り込めませんでした
  • 目的は壊れたデータを含むWebデータから有効な文字だけ取り出して処理することです。

よろしくお願いします。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2019/11/02 00:41

追記してください。プラットフォームのネイティブエンコーディングは何ですか。WebサイトAのJSONファイルのエンコーディングは何ですか。JSONファイルをFileReaderで読むと、何も指定しなければプラットフォームのネイティブエンコーディングからUnicodeに変換するが、大丈夫かな。inはUnicodeとしてコードを書いているが、すでにおかしくなっているかもしれん。えーと、定数の比較はequalsじゃなくて==で良さそうだが。
guest

回答1

0

ベストアンサー

UnicodeBlock.of(ch) が null を返しているのだと思われるので、Unicode として全く成立していない文字は処理対象として迂回する必要があるのだろうと思います。

恐らく、次で回避できるのではないでしょうか。

Java

1Character.UnicodeBlock block = Character.UnicodeBlock.of(ch); 2if (block == null) { 3 continue; 4} 5 6boolean condition1 = block.equals(CJK_UNIFIED_IDEOGRAPHS); 7boolean condition2 = block.equals(BASIC_LATIN); 8//以下省略

根拠:Character.UnicodeBlock.of(char)の Javadoc に次のように書いてあるので。

public static Character.UnicodeBlock of(char c)

 
指定された文字が含まれているUnicodeブロックを表すオブジェクトを返します。ただし、その文字がすでに定義されているブロックのメンバーでない場合にはnullを返します。
注: このメソッドは、補助文字を処理できません。補助文字を含むすべてのUnicode文字をサポートするには、of(int)メソッドを使用してください。

パラメータ:
c - 該当する文字

戻り値:
この文字をメンバーとして持つUnicodeブロックを表すUnicodeBlockのインスタンス。文字がどのUnicodeブロックのメンバーでもない場合はnull

== 補足 ==
もし補助文字で問題になっているのなら、上の Javadoc に書いてある通り of(int) を使うように変えれば良いと思います(補助文字は端折って言うと「サロゲートペア」で表現される文字です。詳しくはネット等で確認してください)。
その場合は in が String だとして、 toCharArray() するのでなく、codePointAt(int)codePoints() などを使って、Unicode のコード・ポイントを取得して処理するのが良いように思えます。

ただし、この of(int) メソッドに変え補助文字まで対象範囲を拡げたとしても、Unicode として成立していない場合は null が返されることが Javadoc に記載されているので、 NullPointerException 対策は上記の通り必要だと思います。

投稿2019/11/02 00:41

ironya

総合スコア456

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

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

R.Mizukami

2019/11/02 04:57

ironya さんの回答のとおり `UnicodeBlock.of(ch)` が null になるのが問題なら、 equals メソッドの呼び出しと引数を逆にして `CJK_UNIFIED_IDEOGRAPHS.equals(Character.UnicodeBlock.of(ch))` のようにすれば条件分岐で continue させる必要はなさそうですね。
ironya

2019/11/02 06:37

NullPointerException の未然の策として一般的にその書き方の方が良いとされていますね。
beyond_the_avg

2019/11/04 21:38

ありがとうございます。大変ためになりました。お恥ずかしながら先入観を持って問題点を見ていたため、UnicodeBlock.of(ch)がnullであるという極めて初歩的なことを見落としていました。なお、文字化けした文字はUnicode BlockではcodePointがSPECIALSになっていて、未定義ではありませんでした。しかし、UnicodeBlock.of(ch)はnullが返ってくるのでそのへんの疑問はまだ残っています。
ironya

2019/11/05 00:57 編集

手元の環境で \uFFF0~\uFFFF の文字で試してみましたけども、UnicodeBlock.of(char), UnicodeBlock.of(int) のどちらも UnicodeBlock.SPECIALS が返されました。 JREは以下の通り。ご参考まで。 MacOS 10.15 java version "1.8.0_181" Java(TM) SE Runtime Environment (build 1.8.0_181-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問