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

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

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

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

Unicode

Unicodeはエンコーディングの標準規格です。1つの文字コード体系で多国語の表現を可能にすることを目指して作られています。

Q&A

解決済

2回答

3973閲覧

BreakIterator.getCharacterInstanceがロケールを引数に取りますが、どう使われるでしょうか

yuba

総合スコア5568

Java

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

Unicode

Unicodeはエンコーディングの標準規格です。1つの文字コード体系で多国語の表現を可能にすることを目指して作られています。

0グッド

1クリップ

投稿2016/07/08 11:04

Javaで文字列の「人間にとっての文字数」を数えるにはtoString()ではダメです。サロゲートペア文字が2文字にカウントされてしまいます。codePointCount()も惜しいのですがダメです。異体字セレクタ込みの文字や互換分解された文字が複数文字にカウントされてしまいます。

ではどうするかというとBreakIterator.getCharacterInstanceを使って人間にとっての文字をイテレートしてもらうというのが正解になるのですが、このメソッド、Localeを引数に取ります。

同じクラスのgetSentenceInstance(文を列挙)とかgetWordInstance(単語を列挙)とかなら思い切りロケール依存しますんでロケールを引数に取るのもわかるのですが、getCharacterInstanceはロケールをどのように使うのでしょうか。

そして、より直接的な質問の目的なのですが、言語非依存なサーバプログラムを書こうというときにはなんのロケールを指定すべきなんでしょうか。
(getAvailableLocalesの仕様を呼んでいると、USを指定するのが確実なのかとも思いますが)

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

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

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

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

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

guest

回答2

0

ベストアンサー

getCharacterInstanceはロケールをどのように使うのでしょうか。

getCharacterInstanceメソッドの戻り値であるBreakIteratorクラスのAPIリファレンスにある、以下の記述が回答になるかと思います。
https://docs.oracle.com/javase/jp/8/docs/api/java/text/BreakIterator.html

返される境界は、補助文字、結合文字シーケンス、または合字クラスタの境界になる場合があります。たとえば、アクセント付きの文字は、基準文字と発音区別符号として格納されている場合があります。ユーザーの文字に対する認識は言語間で異なります。

で、ウィキペディアの"合字"に関する項を読んでみると、以下のように書いてあります。
https://ja.wikipedia.org/wiki/%E5%90%88%E5%AD%97

合字(ごうじ)またはリガチャー(英: Ligature)とは、複数の文字を合成して一文字にしたもの。

(中略)

インド系文字のほとんどは複数の文字を合成して一音節の音(言語によっては複数の音節で読まれる)を表す字を作るシステムになっている。文字コード上では合字は一部のもの(ॐ などの表意文字として機能する字等)を除いて単独の文字として存在せず、複数の特定の文字を決まった順番で並べた際に1文字の合字として扱われるシステムになっている。

このような文字を正しく「1文字」と判定するためには、やはりロケールを指定してやる必要があるのではないでしょうか?
なぜなら、例えば
「複数のロケールで使用されている文字体系の中に、ある特定のロケールにだけ存在する合字」
とうものも、可能性としてあり得ると思うからです。

言語非依存なサーバプログラムを書こうというときにはなんのロケールを指定すべきなんでしょうか。

上記の理由から、これには正解は無いように思います。
getAvailableLocalesメソッドの

これには、Locale.USと等価なLocaleインスタンスが少なくとも1つ含まれている必要があります。

という記述も、おそらくJavaランタイムが最低限、サポートしなければならないロケールがen_USだからではないかと推測します。
http://www.oracle.com/technetwork/articles/javase/locale-140624.html#supported

there is no requirement that all runtime implementations support the same set of locales. But all implementations must support a minimal list of them. This list is quite short: English (U.S.).

すべてのランタイム実装は同じロケールのセットをサポートしている必要はありません。 しかし、すべての実装は最小限のリストをサポートしている必要があります。 このリストは非常に短いです:英語(米国)

ちなみに、本回答にあたりgetCharacterInstanceメソッドのソースコードを読んでみようとしましたが、私には理解不可能でした(^^;
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/text/BreakIterator.java#BreakIterator.getCharacterInstance%28java.util.Locale%29

2016/07/11 追記

他のものと異なる文字数をカウントするロケールを検出するプログラム。
-enableassertionsオプションを付けて実行してください。
http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html

java

1import java.text.BreakIterator; 2import java.util.Collections; 3import java.util.HashMap; 4import java.util.Locale; 5import java.util.Map; 6 7public class Main { 8 9 private static final Map<String, Integer> TESTER; 10 static { 11 Map<String, Integer> tester = new HashMap<String, Integer>(); 12 tester.put("Julius Cæsar", 12); // 合字 13 tester.put("\u0075\u0308\u0304", 1); // 合字 14 tester.put("\u30DB\u309A", 1); // 合字 15 tester.put("㍿", 1); // 合字 16 tester.put("キャリーパミュパミュ", 12); // 半角カナ 17 tester.put("㌦亞䖸丿塔", 5); // 旧字・異字体 18 tester.put("कवि की उमंग उल्का मुट्ठी", 14); // ヒンドゥー後 19 tester.put( 20 "\u05DC\u05B4\u05D4\u05B0\u05D9\u05D5\u05B9\u05EA\u0020\u05E2\u05B7\u05DD\u0020\u05D7\u05B8\u05E4\u05B0\u05E9\u05B4\u05C1\u05D9\u0020\u05D1\u05B0\u05BC\u05D0\u05B7\u05E8\u05B0\u05E6\u05B5\u05E0\u05D5\u05BC\u0020\u05D0\u05B6\u05E8\u05B6\u05E5\u0020\u05E6\u05B4\u05D9\u05BC\u05D5\u05B9\u05DF\u0020\u05D5\u05B4\u05D9\u05E8\u05D5\u05BC\u05E9\u05B8\u05C1\u05DC\u05B7\u05D9\u05B4\u05DD", 21 38); // ヘブライ語、右から読む 22 23 TESTER = Collections.unmodifiableMap(tester); 24 } 25 26 private static final String ERROR_MESSAGE = "Locale=%s, text=%s, expected=%d, detected=%d"; 27 28 public static void main(String[] args) { 29 for (Map.Entry<String, Integer> tester : TESTER.entrySet()) { 30 for (Locale locale : Locale.getAvailableLocales()) { 31 int count = countCharactor(tester.getKey(), locale); 32 assert count == tester.getValue() : String.format(ERROR_MESSAGE, 33 locale.toLanguageTag(), tester.getKey(), tester.getValue(), count); 34 } 35 } 36 } 37 38 private static int countCharactor(String text, Locale locale) { 39 BreakIterator iterator = BreakIterator.getCharacterInstance(locale); 40 iterator.setText(text); 41 42 int count = 0; 43 while (iterator.next() != BreakIterator.DONE) { 44 count++; 45 } 46 return count; 47 } 48}

投稿2016/07/08 14:43

編集2016/07/10 16:11
KiyoshiMotoki

総合スコア4791

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

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

yuba

2016/07/08 23:43

> このような文字を正しく「1文字」と判定するためには、やはりロケールを指定してやる必要があるのではないでしょうか? そういう文字、本当にあるのでしょうか。 ある文化圏では1文字だけどある文化圏では2文字と扱う文字があり、それらが包摂もされずにUnicodeに収載されている事例が。 いや、あるんだとしてそれがどういう文字だか仕様として明示されていないとプログラミングできないんですよね。 それで困っております。
KiyoshiMotoki

2016/07/10 16:11

返信ありがとうございます。 > そういう文字、本当にあるのでしょうか。 > ある文化圏では1文字だけどある文化圏では2文字と扱う文字があり、それらが包摂もされずにUnicodeに収載されている事例が。 「そういう文字」を探してみましたが、見つけることができませんでした。 (むしろ、どのように探せばよいか見当がつきませんでしたorz) 代わりに、回答欄に追記したコードで いくつか思いついた、ロケール依存しそうな文字の文字数をカウントしてみましたが、 私の環境(Mac OSX10.9, JDK1.7) では、どのロケールでも文字数は変わりませんでした。 私の元の回答と異なる結果となり恐縮ですが、 sipadan2003様の回答の通り現状はロケール依存しておらず、 APIリファレンスの記述は将来の拡張のための余地を残しているに過ぎないのかもしれませんね。 だとすれば、`getCharacterInstance`メソッドに渡すロケールは`en_US`がよさそうです。 これなら、(言語に依存する可能性は残るとしても)少なくとも実行環境には依存しないプログラムにすることができますので。
ikedas

2016/10/29 05:19 編集

「そういう文字」としては、次のようなものがありますね。 - オランダ語の「IJ」 https://ja.wikipedia.org/wiki/IJ - チェコ語やスロバキア語の「Ch」https://ja.wikipedia.org/wiki/Ch - スロバキア語の「Dz」 ユニコードでは、これらの合字に単独の符号を割り当てている場合もありますが、その場合も正規化すると2文字分の符号で表されます。 もっともこれらの例に挙げた文字については、Javaの標準クラスでもICUで拡張されたほうでも、BreakIteratorでロケール毎の取り扱いをしてはいないようです。
yuba

2016/10/29 07:43

実例ありがとうございます。 世界は広いですね、ijは一文字とも二文字ともつかないとか。 なるほど、これがロケールの必要性ですか。
KiyoshiMotoki

2016/10/29 09:02

ikedas様 コメントありがとうございます。 私も勉強させていただきました。
guest

0

KiyoshiMotokiさんのご回答、とても好感が持てますね。誠意を感じます。

java

1final Locale[] locales = new Locale[]{ 2 Locale.US, 3 Locale.JAPANESE, 4 Locale.forLanguageTag("hi_IN") 5}; 6 7Stream.of(locales) 8 .map(locale->BreakIterator.getCharacterInstance(locale)) 9 .map(bi->bi.getClass().getName()) 10 .forEach(System.out::println);

実行結果は、次の通りでした。

sun.util.locale.provider.RuleBasedBreakIterator sun.util.locale.provider.RuleBasedBreakIterator sun.util.locale.provider.RuleBasedBreakIterator

sun.util.locale.provider.RuleBasedBreakIteratorをデコンパイルして調べるのが手っ取り早そうです。

投稿2016/07/09 12:35

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2016/07/09 18:19 編集

コードを追って見た限り、最終的にはロケールに関わらず、 jre/lib/resources.jarのsun.text.resources.CharacterBreakIteratorData がロードされるようで、ロケールに依存しないように見えます。 実際にデバッグしたりしたわけではないので、今のところ断言はできません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問