程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 計算機程序的思維邏輯 (28),思維28

計算機程序的思維邏輯 (28),思維28

編輯:JAVA綜合教程

計算機程序的思維邏輯 (28),思維28


本節探討Character類,它的基本用法我們在包裝類第一節已經介紹了,本節不再贅述。Character類除了封裝了一個char外,還有什麼可介紹的呢?它有很多靜態方法,封裝了Unicode字符級別的各種操作,是Java文本處理的基礎,注意不是char級別,Unicode字符並不等同於char,本節詳細介紹這些方法以及相關的Unicode知識。

在介紹這些方法之前,我們需要回顧一下字符在Java中的表示方法,我們在第六節、第七節、第八節介紹過編碼、Unicode、char等知識,我們先簡要回顧一下。

Unicode基礎

Unicode給世界上每個字符分配了一個編號,編號范圍從0x000000到0x10FFFF。編號范圍在0x0000到0xFFFF之間的字符,為常用字符集,稱BMP(Basic Multilingual Plane)字符。編號范圍在0x10000到0x10FFFF之間的字符叫做增補字符(supplementary character)。

Unicode主要規定了編號,但沒有規定如果把編號映射為二進制,UTF-16是一種編碼方式,或者叫映射方式,它將編號映射為兩個或四個字節,對BMP字符,它直接用兩個字節表示,對於增補字符,使用四個字節,前兩個字節叫高代理項(high surrogate),范圍從0xD800到0xDBFF,後兩個字節叫低代理項(low surrogate),范圍從0xDC00到0xDFFF,UTF-16定義了一個公式,可以將編號與四字節表示進行相互轉換。

Java內部采用UTF-16編碼,char表示一個字符,但只能表示BMP中的字符,對於增補字符,需要使用兩個char表示,一個表示高代理項,一個表示低代理項。

使用int可以表示任意一個Unicode字符,低21位表示Unicode編號,高11位設為0。整數編號在Unicode中一般稱為代碼點(Code Point),表示一個Unicode字符,與之相對,還有一個詞代碼單元(Code Unit)表示一個char。

Character類中有很多相關靜態方法,讓我們來看一下。

檢查code point和char

判斷一個int是不是一個有效的代碼單元:

public static boolean isValidCodePoint(int codePoint) 

小於等於0x10FFFF的為有效,大於的為無效。

判斷一個int是不是BMP字符:

public static boolean isBmpCodePoint(int codePoint) 

小於等於0xFFFF的為BMP字符,大於的不是。

判斷一個int是不是增補字符:

public static boolean isSupplementaryCodePoint(int codePoint)

0x010000和0X10FFFF之間的為增補字符。

判斷char是否是高代理項:

public static boolean isHighSurrogate(char ch) 

0xD800到0xDBFF為高代理項。

判斷char是否為低代理項:

public static boolean isLowSurrogate(char ch) 

0xDC00到0xDFFF為低代理項。

判斷char是否為代理項:

public static boolean isSurrogate(char ch) 

char為低代理項或高代理項,則返回true。

判斷兩個字符high和low是否分別為高代理項和低代理項:

public static boolean isSurrogatePair(char high, char low) 

判斷一個代碼單元由幾個char組成:

public static int charCount(int codePoint) 

增補字符返回2,BMP字符返回1。

code point與char的轉換

除了簡單的檢查外,Character類中還有很多方法,進行code point與char的相互轉換。

根據高代理項high和低代理項low生成代碼單元:

public static int toCodePoint(char high, char low)

這個轉換有個公式,這個方法封裝了這個公式。

根據代碼單元生成char數組,即UTF-16表示:

public static char[] toChars(int codePoint) 

如果code point為BMP字符,則返回的char數組長度為1,如果為增補字符,長度為2,char[0]為高代理項,char[1]為低代理項。

將代碼單元轉換為char數組:

public static int toChars(int codePoint, char[] dst, int dstIndex) 

與上面方法類似,只是結果存入指定數組dst的指定位置index。

對增補字符code point,生成高代理項和低代理項:

public static char lowSurrogate(int codePoint)
public static char highSurrogate(int codePoint) 

按code point處理char數組或序列

Character包含若干方法,以方便按照code point來處理char數組或序列。

返回char數組a中從offset開始count個char包含的code point個數:

public static int codePointCount(char[] a, int offset, int count) 

比如說,如下代碼輸出為2,char個數為3,但code point為2。

char[] chs = new char[3];
chs[0] = '馬';
Character.toChars(0x1FFFF, chs, 1);
System.out.println(Character.codePointCount(chs, 0, 3));

除了接受char數組,還有一個重載的方法接受字符序列CharSequence:

public static int codePointCount(CharSequence seq, int beginIndex, int endIndex)

CharSequence是一個接口,它的定義如下所示:

public interface CharSequence {
    int length();
    char charAt(int index);
    CharSequence subSequence(int start, int end);
    public String toString();
}

它與一個char數組是類似的,有length方法,有charAt方法根據索引獲取字符,String類就實現了該接口。

返回char數組或序列中指定索引位置的code point:

public static int codePointAt(char[] a, int index)
public static int codePointAt(char[] a, int index, int limit)
public static int codePointAt(CharSequence seq, int index) 

如果指定索引位置為高代理項,下一個位置為低代理項,則返回兩項組成的code point,檢查下一個位置時,下一個位置要小於limit,沒傳limit時,默認為a.length。

返回char數組或序列中指定索引位置之前的code point:

public static int codePointBefore(char[] a, int index)
public static int codePointBefore(char[] a, int index, int start)
public static int codePointBefore(CharSequence seq, int index)

與codePointAt不同,codePoint是往後找,codePointBefore是往前找,如果指定位置為低代理項,且前一個位置為高代理項,則返回兩項組成的code point,檢查前一個位置時,前一個位置要大於等於start,沒傳start時,默認為0。

根據code point偏移數計算char索引:

public static int offsetByCodePoints(char[] a, int start, int count,
                                         int index, int codePointOffset)
public static int offsetByCodePoints(CharSequence seq, int index,
                                         int codePointOffset)

如果字符數組或序列中沒有增補字符,返回值為index+codePointOffset,如果有增補字符,則會將codePointOffset看做code point偏移,轉換為字符偏移,start和count取字符數組的子數組。

比如,我們看如下代碼:

char[] chs = new char[3];
Character.toChars(0x1FFFF, chs, 1);
System.out.println(Character.offsetByCodePoints(chs, 0, 3, 1, 1));

輸出結果為3,index和codePointOffset都為1,但第二個字符為增補字符,一個code point偏移是兩個char偏移,所以結果為3。

字符屬性

我們之前說,Unicode主要是給每個字符分配了一個編號,其實,除了分配編號之外,還分配了一些屬性,Character類封裝了對Unicode字符屬性的檢查和操作,我們來看一些主要的屬性。

獲取字符類型(general category):

public static int getType(int codePoint)
public static int getType(char ch)

Unicode給每個字符分配了一個類型,這個類型是非常重要的,很多其他檢查和操作都是基於這個類型的。

getType方法的參數可以是int類型的code point,也可以是char類型,char只能處理BMP字符,而int可以處理所有字符,Character類中很多方法都是既可以接受int,也可以接受char,後續只列出int類型的方法。

返回值是int,表示類型,Character類中定義了很多靜態常量表示這些類型,下表列出了一些字符,type值,以及Character類中常量的名稱:

字符 type值 常量名稱 'A'
1
UPPERCASE_LETTER 'a'
2
LOWERCASE_LETTER '馬' 5
OTHER_LETTER '1'
9
DECIMAL_DIGIT_NUMBER ' '
12
SPACE_SEPARATOR '\n'
15
CONTROL '-'
20 DASH_PUNCTUATION '{'
21
START_PUNCTUATION '_'
23
CONNECTOR_PUNCTUATION '&'
24
OTHER_PUNCTUATION '<'
25
MATH_SYMBOL '$'
26
CURRENCY_SYMBOL

 檢查字符是否在Unicode中被定義:

public static boolean isDefined(int codePoint) 

每個被定義的字符,其getType()返回值都不為0,如果返回值為0,表示無定義。注意與isValidCodePoint的區別,後者只要數字不大於0x10FFFF都返回true。

檢查字符是否為數字:

public static boolean isDigit(int codePoint)

getType()返回值為DECIMAL_DIGIT_NUMBER的字符為數字,需要注意的是,不光字符'0','1',...'9'是數字,中文全角字符的0到9,即'0','1','9'也是數字。比如說:

char ch = '9'; //中文全角數字
System.out.println((int)ch+","+Character.isDigit(ch));

輸出為:

65305,true

全角字符的9,Unicode編號為65305,它也是數字。

檢查是否為字母(Letter):

public static boolean isLetter(int codePoint)

如果getType()的返回值為下列之一,則為Letter:

UPPERCASE_LETTER
LOWERCASE_LETTER
TITLECASE_LETTER
MODIFIER_LETTER
OTHER_LETTER

除了TITLECASE_LETTER和MODIFIER_LETTER,其他我們上面已經看到過了,而這兩個平時碰到的也比較少,就不介紹了。

檢查是否為字母或數字

public static boolean isLetterOrDigit(int codePoint)

只要其中之一返回true就返回true。

檢查是否為字母(Alphabetic)

public static boolean isAlphabetic(int codePoint)

這也是檢查是否為字母,與isLetter的區別是,isLetter返回true時,isAlphabetic也必然返回true,此外,getType()值為LETTER_NUMBER時,isAlphabetic也返回true,而isLetter返回false。Letter_NUMBER中常見的字符有羅馬數字字符,如:'Ⅰ','Ⅱ','Ⅲ','Ⅳ'。

檢查是否為空格字符

public static boolean isSpaceChar(int codePoint)

getType()值為SPACE_SEPARATOR,LINE_SEPARATOR和PARAGRAPH_SEPARATOR時,返回true。這個方法其實並不常用,因為它只能嚴格匹配空格字符本身,不能匹配實際產生空格效果的字符,如tab控制鍵'\t'。

更常用的檢查空格的方法

public static boolean isWhitespace(int codePoint) 

'\t','\n',全角空格' ',和半角空格' '的返回值都為true。

檢查是否為小寫字符

public static boolean isLowerCase(int codePoint) 

常見的主要就是小寫英文字母a到z。

檢查是否為大寫字符

public static boolean isUpperCase(int codePoint)

常見的主要就是大寫英文字母A到Z。

檢查是否為表意象形文字

public static boolean isIdeographic(int codePoint) 

大部分中文都返回為true。

檢查是否為ISO 8859-1編碼中的控制字符

public static boolean isISOControl(int codePoint) 

我們在第6節介紹過,0到31,127到159表示控制字符。

檢查是否可作為Java標示符的第一個字符

public static boolean isJavaIdentifierStart(int codePoint) 

Java標示符是Java中的變量名、函數名、類名等,字母(Alphabetic),美元符號($),下劃線(_)可作為Java標示符的第一個字符,但數字字符不可以。

檢查是否可作為Java標示符的中間字符

public static boolean isJavaIdentifierPart(int codePoint) 

相比isJavaIdentifierStart,主要多了數字字符,中間可以有數字。

檢查是否為鏡像(mirrowed)字符

public static boolean isMirrored(int codePoint)

常見鏡像字符有( ) { } < > [ ],都有對應的鏡像。

字符轉換

Unicode除了規定字符屬性外,對有大小寫對應的字符,還規定了其對應的大小寫,對有數值含義的字符,也規定了其數值。

我們先來看大小寫,Character有兩個靜態方法,對字符進行大小寫轉換:

public static int toLowerCase(int codePoint)
public static int toUpperCase(int codePoint)

這兩個方法主要針對英文字符a-z和A-Z, 例如:toLowerCase('A')返回'a',toUpperCase('z')返回'Z'。

返回一個字符表示的數值:

public static int getNumericValue(int codePoint)  

字符'0'到'9'返回數值0到9,對於字符a到z,無論是小寫字符還是大寫字符,無論是普通英文還是中文全角,數值結果都是10到35,例如,如下代碼的輸出結果是一樣的,都是10。

System.out.println(Character.getNumericValue('A')); //全角大寫A
System.out.println(Character.getNumericValue('A'));
System.out.println(Character.getNumericValue('a')); //全角小寫a
System.out.println(Character.getNumericValue('a'));

返回按給定進制表示的數值:

public static int digit(int codePoint, int radix) 

radix表示進制,常見的有2/8/10/16進制,計算方式與getNumericValue類似,只是會檢查有效性,數值需要小於radix,如果無效,返回-1,例如:

digit('F',16)返回15,是有效的,但digit('G',16)就無效,返回-1。

返回給定數值的字符形式

public static char forDigit(int digit, int radix) 

與digit(int codePoint, int radix)相比,進行相反轉換,如果數字無效,返回'\0'。例如,Character.forDigit(15, 16)返回'F'。

與Integer類似,Character也有按字節翻轉:

public static char reverseBytes(char ch)

例如,翻轉字符0x1234:

System.out.println(Integer.toHexString(
                Character.reverseBytes((char)0x1234)));

輸出為3412。

小結

本節詳細介紹了Characer類以及相關的Unicode知識,Character類在Unicode字符級別,而非char級別,封裝了字符的各種操作,通過將字符處理的細節交給Character類,其他類就可以在更高的層次上處理文本了。

至此,關於包裝類我們就介紹完了。下一節,讓我們在Character的基礎上,進一步探索字符串類String。

----------------

未完待續,查看最新文章,敬請關注微信公眾號“老馬說編程”(掃描下方二維碼),從入門到高級,深入淺出,老馬和你一起探索Java編程及計算機技術的本質。用心寫作,原創文章,保留所有版權。

-----------

相關好評原創文章

計算機程序的思維邏輯 (6) - 如何從亂碼中恢復 (上)?

計算機程序的思維邏輯 (7) - 如何從亂碼中恢復 (下)?

計算機程序的思維邏輯 (8) - char的真正含義

計算機程序的思維邏輯 (26) - 剖析包裝類 (上)

計算機程序的思維邏輯 (27) - 剖析包裝類 (中)

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved