JAVA中文比較問(wèn)題的分析和解決是怎樣的

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

成都創(chuàng)新互聯(lián)公司從2013年開(kāi)始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元中站做網(wǎng)站,已為上家服務(wù),為中站各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18982081108

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

以下是String.java中compareTo的源代碼,請(qǐng)注意其中的注釋:

public class String

{

  …

  public int compareTo(String anotherString) {

  int len1 = count;

  int len2 = anotherString.count;

 

 

 //n為兩個(gè)字符串長(zhǎng)度的最小者

 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是第一個(gè)存儲(chǔ)索引

 

  int i = offset;

  int j = anotherString.offset;

 

  //如果i == j

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

  // 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://直到找到一個(gè)不相等的字符,返回c1 - c2

  return c1 - c2;

  k++;

    }

  } else {

    while (n-- != 0) file://直到兩個(gè)字符串長(zhǎng)度記數(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)的情況是:兩個(gè)字符串比較完之后還沒(méi)有得到結(jié)果。相等的情況

  }

}//end of class String

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

  char c1 = v1[k];

  char c2 = v2[k];

可是當(dāng)Java使用GB2312編碼時(shí),一個(gè)對(duì)漢字所獲取到的Char值卻是不規(guī)則的,即一個(gè)漢字在Java中作為一個(gè)char來(lái)處理(雙字節(jié)字符)時(shí),將這樣的雙字節(jié)字符進(jìn)行強(qiáng)制轉(zhuǎn)換成int類型時(shí),所得到的不是包含了漢字編碼順序的中文內(nèi)碼。可以看一下一組測(cè)試數(shù)據(jù)可以看到其中奧妙:

字符

Char值

Byte[]值

按Byte[]合成的值

25105

[50:46]

[-5046]

愛(ài)

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)該在“愛(ài)”字后面,因此理論上來(lái)講"我"字的Char值應(yīng)該比“愛(ài)"字的char值要大。可是不知道為什么Java的漢字char(兩個(gè)byte)->int類型的轉(zhuǎn)換會(huì)發(fā)生很大偏差。而失去了漢字原本在GBK規(guī)范當(dāng)中,按內(nèi)碼排列好的順序。但從一個(gè)漢字拆分成2個(gè)字節(jié)的byte[]時(shí),所得到的值并沒(méi)有打亂GBK編碼規(guī)定的順序,因此得到解決問(wèn)題的思路:將String進(jìn)行GB2312編碼后取得某個(gè)漢字獲取其Char值時(shí),將漢字拆分成2個(gè)字節(jié)byte[]再進(jìn)行計(jì)算,從而得到正確的內(nèi)碼。

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

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

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

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

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

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;

  }

 

//獲取一個(gè)漢字/字母的Char值

  public static int getCharCode(String s)

  {

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

byte [] b = s.getBytes();

  int value = 0;

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

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

  {

  value = value * 100 + b[i];

  }

  return value;

  }

 

//比較兩個(gè)字符串

  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中文比較問(wèn)題的分析和解決是怎樣的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

本文名稱:JAVA中文比較問(wèn)題的分析和解決是怎樣的
分享URL:http://muchs.cn/article6/jpgeig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、全網(wǎng)營(yíng)銷推廣、網(wǎng)站制作、響應(yīng)式網(wǎng)站、網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)