Java で Unicode エージェント プログラミングを使用する方法
シーケンシャル アクセス
シーケンシャル アクセスは、Java 言語で文字列を処理するための基本的な操作です。このアプローチでは、入力文字列内の各文字は最初から最後まで、または場合によっては最後から最初まで順番にアクセスされます。このセクションでは、シーケンシャル アクセス方式を使用して文字列から 32 ビット コード ポイント配列を作成する 7 つの技術例について説明し、その処理時間を見積もります。
例 1-1: ベンチマーク (サロゲート ペアはサポートされていません)
リスト 1 16 ビットの char 型値を 32 ビットのコード ポイント値に直接割り当てますサロゲート ペアを考慮します。
リスト 1. サロゲート ペアはサポートされません
int[] toCodePointArray(String str) { // Example 1-1 int len = str.length(); // the length of str int[] acp = new int[len]; // an array of code points for (int i = 0, j = 0; i <p>この例はサロゲート ペアをサポートしていませんが、処理時間のベースラインを提供します。後続のシーケンスを比較するには、例を参照してください。 </p><p><strong>例 1-2: isSurrogatePair() の使用</strong></p><p>リスト 2 isSurrogatePair() を使用して、サロゲート ペアの総数をカウントします。カウント後、値を格納するコード ビットの配列に十分なメモリが割り当てられます。次に、isHighSurrogate() と isLowSurrogate() を使用して、順次アクセス ループに入り、各サロゲート ペア文字が上位サロゲートであるか下位サロゲートであるかを判断します。上位サロゲートに続いて下位サロゲートが見つかった場合、 toCodePoint() を使用してサロゲート ペアをコード ポイント値に変換し、現在のインデックス値を 2 ずつ増分します。それ以外の場合は、char 型の値をコード ポイント値に直接割り当て、現在のインデックス値を 1 ずつ増分します。この例は、例 1-1 よりも処理に 1.38 倍の時間がかかります。 </p><p><strong>リスト 2. 限定的なサポート</strong></p><pre class="brush:php;toolbar:false">int[] toCodePointArray(String str) { // Example 1-2 int len = str.length(); // the length of str int[] acp; // an array of code points int surrogatePairCount = 0; // the count of surrogate pairs for (int i = 1; i <p>リスト 2 のソフトウェアを更新するアプローチは単純です。これは面倒で大規模な変更が必要なため、結果として得られるソフトウェアは脆弱になり、将来の変更が困難になります。具体的には、これらの問題は次のとおりです。</p>#◆十分なメモリを割り当てるためにコード ポイントの数を計算する必要がある<p>#◆文字列内の指定されたインデックスの正しいコード ポイント値を取得することが困難</p> <p>◆現在のインデックスを次の処理ステップに正しく移動するのは困難です</p><p>次の例では、改良されたアルゴリズムを示します。 </p><p></p>例: 基本サポート<p><strong></strong>Java 1.5 では、例 1-2 の 3 つの問題をそれぞれ処理する codePointCount()、codePointAt()、および offsetByCodePoints() メソッドが提供されています。リスト 3 では、次のメソッドを使用して、このアルゴリズムの読みやすさを向上させています。 </p><p></p>リスト 3. 基本サポート<p><strong><pre class="brush:php;toolbar:false">int[] toCodePointArray(String str) { // Example 1-3 int len = str.length(); // the length of str int[] acp = new int[str.codePointCount(0, len)]; for (int i = 0, j = 0; i
offsetByCodePoints() が 2 番目のパラメーターとして負の数値を受け取ると、コードの先頭からの距離を計算できます。文字列の絶対オフセット値。次に、codePointBefore() は、指定されたインデックスの前のコード ポイント値を返すことができます。これらのメソッドは、リスト 4:
リスト 4 で文字列を末尾から先頭まで走査するために使用されます。 codePointBefore()int[] toCodePointArray(String str) { // Example 1-4 int len = str.length(); // the length of str int[] acp = new int[str.codePointCount(0, len)]; int j = acp.length; // an index for acp for (int i = len; i > 0; i = str.offsetByCodePoints(i, -1)) { acp[--j] = str.codePointBefore(i); } return acp; }
例 1-3 および 1-4 は、基本的なサロゲート ペアのサポートを提供します。これらは一時変数を必要とせず、堅牢なコーディング方法です。処理時間を短縮するには、offsetByCodePoints() の代わりに charCount() を使用するのが効果的ですが、リスト 5 に示すように、コード ポイント値を保持する一時変数が必要です。 charCount() のサポート
int[] toCodePointArray(String str) { // Example 1-5 int len = str.length(); // the length of str int[] acp = new int[str.codePointCount(0, len)]; int j = 0; // an index for acp for (int i = 0, cp; i リスト 5 の処理時間は、例 1-1 の 1.68 倍に短縮されます。 <p><strong></strong>例 1-6: char 配列へのアクセス</p><p></p>リスト 6 例 1-5 に示す最適化を使用しながら、char 型の配列に直接アクセスする:<p> <strong></strong>リスト 6. char 配列の使用のサポートの最適化</p><p></p><pre class="brush:php;toolbar:false">int[] toCodePointArray(String str) { // Example 1-6 char[] ach = str.toCharArray(); // a char array copied from str int len = ach.length; // the length of ach int[] acp = new int[Character.codePointCount(ach, 0, len)]; int j = 0; // an index for acp for (int i = 0, cp; i Char 配列は、toCharArray() を使用して文字列からコピーされます。配列への直接アクセスは、メソッドを介した間接アクセスよりも高速であるため、パフォーマンスが向上します。処理時間は例1-1に比べて1.51倍かかります。ただし、 toCharArray() を呼び出すと、新しい配列を作成し、データを配列にコピーするために、ある程度のオーバーヘッドが必要になります。 String クラスが提供する便利なメソッドも使用できません。ただし、このアルゴリズムは大量のデータを処理する場合に役立ちます。 <p><strong></strong>例 1-7: オブジェクト指向アルゴリズム</p><p></p>この例のオブジェクト指向アルゴリズムでは、リスト 7 に示すように CharBuffer クラスを使用します。 <p> <strong>リスト 7. CharSequence を使用したオブジェクト指向アルゴリズム</strong></p><pre class="brush:php;toolbar:false">int[] toCodePointArray(String str) { // Example 1-7 CharBuffer cBuf = CharBuffer.wrap(str); // Buffer to wrap str IntBuffer iBuf = IntBuffer.allocate( // Buffer to store code points Character.codePointCount(cBuf, 0, cBuf.capacity())); while (cBuf.remaining() > 0) { int cp = Character.codePointAt(cBuf, 0); // the current code point iBuf.put(cp); cBuf.position(cBuf.position() + Character.charCount(cp)); } return iBuf.array(); }
前の例とは異なり、リスト 7 では、順次アクセスのために現在位置を保持するためのインデックスは必要ありません。代わりに、CharBuffer は内部的に現在の位置を追跡します。 Character クラスは、CharSequence インターフェイスを通じて CharBuffers を処理する静的メソッド codePointCount() および codePointAt() を提供します。 CharBuffer は常に現在位置を CharSequence の先頭に設定します。したがって、codePointAt() が呼び出されるとき、2 番目のパラメーターは常に 0 に設定されます。処理時間は例1-1に比べて2.15倍かかります。
处理时间比较
这些顺序访问示例的计时测试使用了一个包含 10,000 个代理对和 10,000 个非代理对的样例字符串。码位数组从这个字符串创建 10,000 次。测试环境包括:
◆OS:Microsoft Windows® XP Professional SP2
◆Java:IBM Java 1.5 SR7
◆CPU:Intel® Core 2 Duo CPU T8300 @ 2.40GHz
◆Memory:2.97GB RAM
表 1 展示了示例 1-1 到 1-7 的绝对和相对处理时间以及关联的 API:
表 1. 顺序访问示例的处理时间和 API
随机访问
随机访问是直接访问一个字符串中的任意位置。当字符串被访问时,索引值基于 16 位 char 类型的单位。但是,如果一个字符串使用 32 位码位,那么它不能使用一个基于 32 位码位的单位的索引访问。必须使用 offsetByCodePoints() 来将码位的索引转换为 char 类型的索引。如果算法设计很糟糕,这会导致很差的性能,因为 offsetByCodePoints() 总是通过使用第二个参数从第一个参数计算字符串的内部。在这个小节中,我将比较三个示例,它们通过使用一个短单位来分割一个长字符串。
示例 2-1:基准测试(不支持代理对)
清单 8 展示如何使用一个宽度单位来分割一个字符串。这个基准测试留作后用,不支持代理对。
清单 8. 不支持代理对
String[] sliceString(String str, int width) { // Example 2-1 // It must be that "str != null && width > 0". List<string> slices = new ArrayList<string>(); int len = str.length(); // (1) the length of str int sliceLimit = len - width; // (2) Do not slice beyond here. int pos = 0; // the current position per char type while (pos <p>sliceLimit 变量对分割位置有所限制,以避免在剩余的字符串不足以分割当前宽度单位时抛出一个 IndexOutOfBoundsException 实例。这种算法在当前位置超出 sliceLimit 时从 while 循环中跳出后再处理最后的分割。</p> <p><strong>示例 2-2:使用一个码位索引</strong></p> <p>清单 9 展示了如何使用一个码位索引来随机访问一个字符串:</p> <p><strong>清单 9. 糟糕的性能</strong></p> <pre class="brush:php;toolbar:false">String[] sliceString(String str, int width) { // Example 2-2 // It must be that "str != null && width > 0". List<string> slices = new ArrayList<string>(); int len = str.codePointCount(0, str.length()); // (1) code point count [Modified] int sliceLimit = len - width; // (2) Do not slice beyond here. int pos = 0; // the current position per code point while (pos <p>清单 9 修改了 清单 8 中的几行。首先,在 Line (1) 中,length() 被 codePointCount() 替代。其次,在 Lines (3)、(4) 和 (6) 中,char 类型的索引通过 offsetByCodePoints() 用码位索引替代。</p> <p>基本的算法流与 示例 2-1 中的看起来几乎一样。但处理时间根据字符串长度与示例 2-1 的比率同比增加,因为 offsetByCodePoints() 总是从字符串头到指定索引计算字符串内部。</p> <p><strong>示例 2-3:减少的处理时间</strong></p> <p>可以使用清单 10 中展示的方法来避免 示例 2-2 的性能问题:</p> <p><strong>清单 10. 改进的性能</strong></p> <pre class="brush:php;toolbar:false">String[] sliceString(String str, int width) { // Example 2-3 // It must be that "str != null && width > 0". List<string> slices = new ArrayList<string>(); int len = str.length(); // (1) the length of str int sliceLimit // (2) Do not slice beyond here. [Modified] = (len >= width * 2 || str.codePointCount(0, len) > width) ? str.offsetByCodePoints(len, -width) : 0; int pos = 0; // the current position per char type while (pos <p>首先,在 Line (2) 中,(清单 9 中的)表达式 len-width 被 offsetByCodePoints(len,-width) 替代。但是,当 width 的值大于码位的数量时,这会抛出一个 IndexOutOfBoundsException 实例。必须考虑边界条件以避免异常,使用一个带有 try/catch 异常处理程序的子句将是另一个解决方案。如果表达式 len>width*2 为 true,则可以安全地调用 offsetByCodePoints(),因为即使所有码位都被转换为代理对,码位的数量仍会超过 width 的值。或者,如果 codePointCount(0,len)>width 为 true,也可以安全地调用 offsetByCodePoints()。如果是其他情况,sliceLimit 必须设置为 0。</p> <p>在 Line (4) 中,清单 9 中的表达式 pos + width 必须在 while 循环中使用 offsetByCodePoints(pos,width) 替换。需要计算的量位于 width 的值中,因为第一个参数指定当 width 的值。接下来,在 Line (5) 中,表达式 pos+=width 必须使用表达式 pos=end 替换。这避免两次调用 offsetByCodePoints() 来计算相同的索引。源代码可以被进一步修改以最小化处理时间。</p> <h3 id="处理时间比较">处理时间比较</h3> <p>图 1 和图 2 展示了示例 2-1、2-2 和 2-3 的处理时间。样例字符串包含相同数量的代理对和非代理对。当字符串的长度和 width 的值被更改时,样例字符串被切割 10,000 次。</p> <p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/164/168337700040575.png" class="lazy" alt="Java で Unicode エージェント プログラミングを使用する方法"></p> <p><strong>图 1. 一个分段的常量宽度</strong></p> <p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/164/168337700041405.png" class="lazy" alt="Java で Unicode エージェント プログラミングを使用する方法"></p> <p><strong>图 2. 分段的常量计数</strong></p> <p>示例 2-1 和 2-3 按照长度比例增加了它们的处理时间,但 示例 2-2 按照长度的平方比例增加了处理时间。当字符串长度和 width 的值增加而分段的数量固定时,示例 2-1 拥有一个常量处理时间,而示例 2-2 和 2-3 以 width 的值为比例增加了它们的处理时间。</p> <h3 id="信息-API">信息 API</h3> <p>大多数处理代理的信息 API 拥有两种名称相同的方法。一种接收 16 位 char 类型参数,另一种接收 32 为码位参数。表 2 展示了每个 API 的返回值。第三列针对 U+53F1,第 4 列针对 U+20B9F,最后一列针对 U+D842(即高代理),而 U+20B9F 被转换为 U+D842 加上 U+DF9F 的代理对。如果程序不能处理代理对,则值 U+D842 而不是 U+20B9F 将导致意想不到的结果(在表 2 中以粗斜体表示)。</p> <p><strong>表 2. 用于代理的信息 API</strong></p> <p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/164/168337700086359.gif" class="lazy" alt="Java で Unicode エージェント プログラミングを使用する方法"></p> <h3 id="其他-API">其他 API</h3> <p>本小节介绍前面的小节中没有讨论的代理对相关 API。表 3 展示所有这些剩余的 API。所有代理对 API 都包含在表 1、2 和 3 中。</p> <p><strong>表 3. 其他代理 API</strong></p> <p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/164/168337700025390.gif" class="lazy" alt="Java で Unicode エージェント プログラミングを使用する方法"></p> <p>清单 11 展示了从一个码位创建一个字符串的 5 种方法。用于测试的码位是 U+53F1 和 U+20B9F,它们在一个字符串中重复了 100 亿次。清单 11 中的注释部分显示了处理时间:</p> <p><strong>清单 11. 从一个码位创建一个字符串的 5 种方法</strong></p> <pre class="brush:php;toolbar:false">int cp = 0x20b9f; // CJK Ideograph Extension B String str1 = new String(new int[]{cp}, 0, 1); // processing time: 206ms String str2 = new String(Character.toChars(cp)); // 187ms String str3 = String.valueOf(Character.toChars(cp)); // 195ms String str4 = new StringBuilder().appendCodePoint(cp).toString(); // 269ms String str5 = String.format("%c", cp); // 3781ms
str1、str2、str3 和 str4 的处理时间没有明显不同。相反,创建 str5 花费的时间要长得多,因为它使用 String.format(),该方法支持基于本地和格式化信息的灵活输出。str5 方法应该只用于程序的末尾来输出文本。
以上がJava で Unicode エージェント プログラミングを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHPは、特に迅速な開発や動的なコンテンツの処理に適していますが、データサイエンスとエンタープライズレベルのアプリケーションには良くありません。 Pythonと比較して、PHPはWeb開発においてより多くの利点がありますが、データサイエンスの分野ではPythonほど良くありません。 Javaと比較して、PHPはエンタープライズレベルのアプリケーションでより悪化しますが、Web開発により柔軟性があります。 JavaScriptと比較して、PHPはバックエンド開発により簡潔ですが、フロントエンド開発のJavaScriptほど良くありません。

PHPとPythonにはそれぞれ独自の利点があり、さまざまなシナリオに適しています。 1.PHPはWeb開発に適しており、組み込みのWebサーバーとRich Functionライブラリを提供します。 2。Pythonは、簡潔な構文と強力な標準ライブラリを備えたデータサイエンスと機械学習に適しています。選択するときは、プロジェクトの要件に基づいて決定する必要があります。

phphassiblasifly-impactedwebdevevermentandsbeyondit.1)itpowersmajorplatformslikewordpratsandexcelsindatabase interactions.2)php'sadaptableability allowsitale forlargeapplicationsusingframeworkslikelavel.3)

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

PHPが多くのWebサイトよりも優先テクノロジースタックである理由には、その使いやすさ、強力なコミュニティサポート、広範な使用が含まれます。 1)初心者に適した学習と使用が簡単です。 2)巨大な開発者コミュニティと豊富なリソースを持っています。 3)WordPress、Drupal、その他のプラットフォームで広く使用されています。 4)Webサーバーとしっかりと統合して、開発の展開を簡素化します。
