溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JAVA中文比較問題的分析和解決是怎樣的

發(fā)布時間:2021-12-08 11:51:17 來源:億速云 閱讀:318 作者:柒染 欄目:編程語言

這篇文章將為大家詳細講解有關(guān)JAVA中文比較問題的分析和解決是怎樣的,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

 Java的中文問題由來已久,前不久需要做內(nèi)存中的中文比較排序,對字符串進行GBK或者GB2312編碼以后,使用String.compareTo方法仍然不能得到正確結(jié)果。因此,懷著懷疑的態(tài)度,對jdk中String類的源代碼做了一翻探究。(使用JDK為1.3.1版本)

以下是String.java中compareTo的源代碼,請注意其中的注釋:

public class String

{

  …

  public int compareTo(String anotherString) {

  int len1 = count;

  int len2 = anotherString.count;

 

 

  //n為兩個字符串長度的最小者

  int n = Math.min(len1, len2);

 

  //獲取字符數(shù)組

  char v1[] = value;

  char v2[] = anotherString.value;

 

  //取偏依位置

  /** The offset is the first index of the storage that is used. */

  //offset 是第一個存儲索引

 

  int i = offset;

  int j = anotherString.offset;

 

  //如果i == j

  //這里可能是判斷取同一內(nèi)存中兩個字符串的情景。。。

  // A  <--  <----

  // B  s1  |

  // C  <--  |

  // D  s2

  // E  |

  // F  |

  // G  <----------

  // 可能這種情況 i = j

  if (i == j) {

    int k = i;

    int lim = n + i;

 

    while (k < lim)

  {

  char c1 = v1[k];

  char c2 = v2[k];

 

  if (c1 != c2) file://直到找到一個不相等的字符,返回c1 - c2

  return c1 - c2;

  k++;

    }

  } else {

    while (n-- != 0) file://直到兩個字符串長度記數(shù)為0

  {

  char c1 = v1[i++]; file://分別取字符

  char c2 = v2[j++];

  if (c1 != c2) {  //發(fā)現(xiàn)不相等立即返回c1 - c2;

  return c1 - c2;

  }

    }

  }

  return len1 - len2;

//最后這里可能出現(xiàn)的情況是: 兩個字符串比較完之后還沒有得到結(jié)果。相等的情況

  }

}//end of class String

為什么Java在做漢字的CompareTo時比較會有問題呢?通過對compareTo源代碼的分析發(fā)現(xiàn),關(guān)鍵在于JDK的compareTo實現(xiàn)是直接使用Char來進行比較的:

  char c1 = v1[k];

  char c2 = v2[k];

可是當Java使用GB2312編碼時,一個對漢字所獲取到的Char值卻是不規(guī)則的,即一個漢字在Java中作為一個char來處理(雙字節(jié)字符)時,將這樣的雙字節(jié)字符進行強制轉(zhuǎn)換成int類型時,所得到的不是包含了漢字編碼順序的中文內(nèi)碼??梢钥匆幌乱唤M測試數(shù)據(jù)可以看到其中奧妙:

字符

Char值

Byte[]值

按Byte[]合成的值

25105

[50:46]

[-5046]

29233

[80:82]

[-8082]

21271

[79:79]

[-7979]

20140

[66:87]

[-6687]

22825

[52:20]

[-5220]

23433

[80:78]

[-8078]

38376

[61:59]

[-6159]

A

65

[-65]

[65]

B

66

[-66]

[66]

C

67

[-67]

[67]

D

68

[-68]

[68]

按照中文順序:“我”字應(yīng)該在“愛”字后面,因此理論上來講"我"字的Char值應(yīng)該比“愛"字的char值要大??墒遣恢罏槭裁碕ava的漢字char(兩個byte)->int類型的轉(zhuǎn)換會發(fā)生很大偏差。而失去了漢字原本在GBK規(guī)范當中,按內(nèi)碼排列好的順序。但從一個漢字拆分成2個字節(jié)的byte[]時,所得到的值并沒有打亂GBK編碼規(guī)定的順序,因此得到解決問題的思路:將String進行GB2312編碼后取得某個漢字獲取其Char值時,將漢字拆分成2個字節(jié)byte[]再進行計算,從而得到正確的內(nèi)碼。

因此我自己寫了下面這樣幾個函數(shù),基本上解決了漢字比較的問題:

  函數(shù)包括三個,你可以隨意放置到任何類當中作為輔助函數(shù)使用(Private Helper)。

n  public int compare(String s1, String s2) :主要工作是為比較做一些前期的編碼工作可以說是系統(tǒng)的一個外殼。

n  public int chineseCompareTo(String s1, String s2):該函數(shù)則是中文字符串比較主體,其內(nèi)部實現(xiàn)了比較的最基本邏輯,和JDK的compareTo所使用的邏輯是一樣的。調(diào)用接口也一樣。

n  public static int getCharCode(String s):該函數(shù)則負責將一個以字符串形式存在的字符轉(zhuǎn)換成為int編碼,兒不損失其位置信息。注意輸入通常是:“我”或者“A”,如果輸入更長的字符串,則改函數(shù)獲得的是第一個字符的值。

private static String __ENCODE__ = "GBK"; file://一定要是GBK

private static String __SERVER_ENCODE__ = "GB2312"; file://服務(wù)器上的缺省編碼

/*

比較兩字符串

*/

  public int compare(String s1, String s2)

  {

  String m_s1 = null, m_s2 = null;

  try

  {

  //先將兩字符串編碼成GBK

  m_s1 = new String ( s1.getBytes(__SERVER_ENCODE__), __ENCODE__);

  m_s2 = new String ( s2.getBytes(__SERVER_ENCODE__), __ENCODE__);

  }

  catch( Exception ex)

  {

  return s1.compareTo(s2);

  }

  int res = chineseCompareTo(m_s1, m_s2);

 

  System.out.println("比較" + s1 + " | " + s2 + "==== Result: " + res);

  return res;

  }

 

//獲取一個漢字/字母的Char

  public static int getCharCode(String s)

  {

  if (s==null && s.equals(“”)) return -1; file://保護代碼

byte [] b = s.getBytes();

  int value = 0;

  //保證取第一個字符(漢字或者英文)

  for (int i = 0; i < b.length && i <= 2; i ++)

  {

  value = value * 100 + b[i];

  }

  return value;

  }

 

//比較兩個字符串

  public int chineseCompareTo(String s1, String s2)

  {

  int len1 = s1.length();

  int len2 = s2.length();

 

  int n = Math.min(len1, len2);

 

  for (int i = 0; i < n; i ++)

  {

  int s1_code = getCharCode(s1.charAt(i) + "");

  int s2_code = getCharCode(s2.charAt(i) + "");

  if (s1_code != s2_code) return s1_code - s2_code;

  }

  return len1 - len2;

  }

關(guān)于JAVA中文比較問題的分析和解決是怎樣的就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI