String#length
とCharacter
にはさまざまなメソッドがあり、コード単位/コードポイントで多かれ少なかれ機能することを知っています。
言語/ロケール、正規化、書記素クラスターなどを考慮して、Unicode標準( AX#29 )で指定された結果を実際に返すJavaで推奨される方法は何ですか?
Java.text.BreakIterator
はテキストを反復処理でき、「文字」、単語、文、行の境界についてレポートできます。
このコードを考えてみましょう:
def length(text: String, locale: Java.util.Locale = Java.util.Locale.ENGLISH) = {
val charIterator = Java.text.BreakIterator.getCharacterInstance(locale)
charIterator.setText(text)
var result = 0
while(charIterator.next() != BreakIterator.DONE) result += 1
result
}
それを実行する:
scala> val text = "Thîs lóo̰ks we̐ird!"
text: Java.lang.String = Thîs lóo̰ks we̐ird!
scala> val length = length(text)
length: Int = 17
scala> val codepoints = text.codePointCount(0, text.length)
codepoints: Int = 21
サロゲートペアの場合:
scala> val parens = "\uDBFF\uDFFCsurpi\u0301se!\uDBFF\uDFFD"
parens: Java.lang.String = ????surpíse!????
scala> val length = length(parens)
length: Int = 10
scala> val codepoints = parens.codePointCount(0, parens.length)
codepoints: Int = 11
scala> val codeunits = parens.length
codeunits: Int = 13
ほとんどの場合、これで十分です。
String.length()
は、文字列内のchar
値( "コード単位")の数を返すものとしてspecifiedです。これは、a Java Stringの長さの最も一般的に役立つ定義です。以下を参照してください。
あなたの説明1 バッキングアレイ/アレイスライスのサイズに基づくlength
のセマンティクスの誤り。 length()
によって返される値がまたであるという事実は、バッキング配列または配列スライスのサイズが単に典型的な実装の詳細Javaクラスライブラリ。String
はそのように実装する必要はありません。実際、 Java文字列の実装は、その方法で実装されていないWASを見たことがあります。
文字列内のUnicodeコードポイントの数を取得するには、str.codePointCount(0, str.length())
を使用します- javadoc を参照してください。
他のエンコーディングで文字列のサイズ(バイト単位)を取得するには、str.getBytes(charset).length
を使用します。
ロケール固有の問題に対処するには、 Normalizer
を使用して、ストリングをユースケースに最も適した形式に正規化し、codePointCount
を次のように使用できます上記。
しかし、場合によってはこれでも機能しないことがあります。例えばUnicode規格が明らかに対応していないハンガリーの文字カウント規則。
ほとんどのアプリケーションがString.length()
を使用する理由は、ほとんどのアプリケーションが人間中心の方法で単語、テキストなどの文字数を数えることに関係していないためです。たとえば、これを行うと:
_String s = "hi mum how are you";
int pos = s.indexOf("mum");
String textAfterMum = s.substring(pos + "mum".length());
_
"mum".length()
がコードポイントを返さないことや、言語的に正しい文字数でないことは、実際には関係ありません。手元の作業に適したモデルで弦の長さを計測しています。そしてそれは機能します。
明らかに、多言語のテキスト分析を行う場合、状況は少し複雑になります。例えば単語を検索します。しかし、それでも、開始する前にテキストとパラメーターを正規化すると、ほとんどの場合、「コードポイント」ではなく「コード単位」で安全にコーディングできます。つまり、length()
は引き続き機能します。
1-この説明は質問の一部のバージョンに関するものでした。十分な担当者がいる場合は、編集履歴を参照してください。
「文字列の長さ」が何を意味するかによって異なります。
String.length()
chars
内の String
の数を返します。これは通常、バッファの割り当てなどの関連タスクのプログラミングにのみ役立ちます。マルチバイトエンコーディングは問題を引き起こす可能性があるため、1つの char
が1つの nicodeコードポイント を意味するわけではありません=。String.codePointCount(int, int)
および Character.codePointCount(CharSequence,int,int)
はどちらも、String
内のUnicodeコードポイントの数を返します。これは通常、マルチバイトエンコーディングの干渉を心配する必要なく、String
を一連のUnicodeコードポイントとして見る必要がある関連タスクのプログラミングにのみ役立ちます。BreakIterator.getCharacterInstance(Locale)
を使用して、次の grapheme を特定のString
で取得 Locale
。これを複数回使用すると、String
内の書記素の数を数えることができます。書記素は基本的に文字であるため(ほとんどの場合)、このメソッドはString
に含まれる書き込み可能な文字の数を取得するのに役立ちます。基本的に、このメソッドは、String
の文字数を手動で数えた場合に得られるのとほぼ同じ数を返します。これにより、データを破損することなく、ユーザーインターフェイスのサイズ変更やStrings
の分割などに役立ちます。さまざまなメソッドのそれぞれがまったく同じデータに対して異なる長さを返す方法を理解するために、 this class を作成して、 this pageに含まれるUnicodeテキストの長さをすばやく生成します 、これは英語以外の文字を使用して多くの異なる言語の包括的なテストを提供するように設計されています。これは、3つの異なる方法で入力ファイルを正規化した後にそのコードを実行した結果です(正規化なし、 [〜#〜] nfc [〜#〜] 、 [〜#〜] nfd [〜#〜] ):
_Input UTF-8 String
>> String.length() = 3431
>> String.codePointCount(int,int) = 3431
>> BreakIterator.getCharacterInstance(Locale) = 3386
NFC Normalized UTF-8 String
>> String.length() = 3431
>> String.codePointCount(int,int) = 3431
>> BreakIterator.getCharacterInstance(Locale) = 3386
NFD Normalized UTF-8 String
>> String.length() = 3554
>> String.codePointCount(int,int) = 3554
>> BreakIterator.getCharacterInstance(Locale) = 3386
_
ご覧のように、String.length()
またはString.codePointCount(int,int)
を使用すると、「同じように見える」String
でも長さの結果が異なる可能性があります。
このトピックおよび他の同様のトピックの詳細については、 このブログ投稿 をお読みください。Unicodeを適切に処理するためのJavaの使用に関するさまざまな基本事項について説明しています。
String.length()
は、文字列を支える配列のサイズを返しませんが、「文字列内のUnicodeコード単位の数」として定義される文字列の実際の長さを返します。 ( APIドキュメント を参照)。
(コメントでスティーブンCが指摘したように、Unicodeコード単位== Java chars)
これがあなたが探しているものではない場合は、質問をもう少し詳しく説明する必要があります。
つまり、言語の文法規則に従って文字列の長さを数えると、答えはノーになります。Javaにはそのようなアルゴリズムはなく、他のどこにもありません。
アルゴリズムがテキストの完全な意味分析も行わない限り、そうではありません。
たとえば、ハンガリー語では、sz
とzs
は、出現する単語の構成に応じて、1文字または2文字として数えることができます(例:ország
は5文字ですが、torzság
は7です。)
Uodate:必要なのがUnicode標準の文字数だけである場合(これは、指摘したように正確ではありません)、文字列をNFKC
に変換します Java.text.Normalizer
が解決策になる可能性があります。