目錄
順序存取
处理时间比较
随机访问
信息 API
其他 API
首頁 Java java教程 Java中如何使用Unicode代理程式設計

Java中如何使用Unicode代理程式設計

May 06, 2023 pm 08:43 PM
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></p>##Java 1.5 提供了 codePointCount()、codePointAt() 和 offsetByCodePoints() 方法來分別處理 範例 1-2 的 3 個問題。清單3 使用這些方法來改善這個演算法的可讀性:<p></p><p>#清單3. 基本支援<strong></strong></p><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 但是,清單3 的處理時間比清單1 長2.8倍。 <p></p><p>範例1-4:使用codePointBefore()<strong></strong></p>當offsetByCodePoints() 接收負數作為第二個參數時,它就能計算出一個距離字串頭的絕對偏移值。接下來,codePointBefore() 能夠傳回一個指定索引前面的碼位值。這些方法用於清單4 中從尾至頭遍歷字串:<p></p><p>清單4. 使用codePointBefore() 的基本支援<strong></strong></p><pre class="brush:php;toolbar:false">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;  }
登入後複製
這個範例的處理時間&mdash ; 比範例1-1 長2.72 倍— 比範例1-3 快一些。通常,當您比較零而不是非零值時,JVM 中的程式碼大小會小一些,有時會提高效能。但是,微小的改進可能不值得犧牲可讀性。

範例 1-5:使用 charCount()

範例 1-3 和 1-4 提供基本的代理對支援。他們不需要任何臨時變量,是健壯的編碼方法。要取得更短的處理時間,使用charCount() 而不是offsetByCodePoints() 是有效的,但需要一個臨時變數來存放碼位值,如清單5 所示:

##清單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 倍。

範例1-6:存取一個char 陣列

清單6 在使用範例1-5 中展示的最佳化的同時直接存取一個char 類型陣列:

清單6. 使用一個char 陣列的最佳化支援

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 類別提供的那些方便的方法也不能被使用。但是,這個演算法在處理大量資料時有用。

範例1-7:一個物件導向的演算法

這個範例的物件導向演算法使用CharBuffer 類,如清單7 所示:

清單7. 使用CharSequence 的物件導向演算法

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 類別提供靜態方法 codePointCount() 和 codePointAt(),它們能透過 CharSequence 介面處理 CharBuffer。 CharBuffer 總是將目前位置設定為 CharSequence 的頭。因此,當 codePointAt() 被呼叫時,第二個參數總是設定為 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

Java中如何使用Unicode代理程式設計

随机访问

随机访问是直接访问一个字符串中的任意位置。当字符串被访问时,索引值基于 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中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java 中的平方根 Java 中的平方根 Aug 30, 2024 pm 04:26 PM

Java 中的平方根

Java 中的完美數 Java 中的完美數 Aug 30, 2024 pm 04:28 PM

Java 中的完美數

Java 中的隨機數產生器 Java 中的隨機數產生器 Aug 30, 2024 pm 04:27 PM

Java 中的隨機數產生器

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java中的Weka

Java 中的阿姆斯壯數 Java 中的阿姆斯壯數 Aug 30, 2024 pm 04:26 PM

Java 中的阿姆斯壯數

Java 中的史密斯數 Java 中的史密斯數 Aug 30, 2024 pm 04:28 PM

Java 中的史密斯數

Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

Java Spring 面試題

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

突破或從Java 8流返回?

See all articles