Java StringTokenizer分隔符拆分字符串
StringTokenizer的成員變量
// 以下七個參數(shù)是在三個參數(shù)的構(gòu)造方法中設(shè)置的 // 當(dāng)前位置 private int currentPosition; // 下一個要處理的字符的索引 private int newPosition; // 最大位置,即被分割字符串的長度 private int maxPosition; // 要分割的字符串 private String str; // 分隔符,字符串中的每個字符都是一個分隔符 private String delimiters; // 指示是否將分隔符作為令牌返回的標(biāo)志。 private boolean retDelims; // 分隔符是否改變的表示,true表示分隔符發(fā)生改變,false表示分隔符沒發(fā)生改變,默認(rèn)為false private boolean delimsChanged; // 以下三個參數(shù)是在構(gòu)造方法的setMaxDelimCodePoint()方法中設(shè)置 // 保存分隔符中ASCII碼值最大的的字符 private int maxDelimCodePoint; // 是否包含代理,即是否涉及到UTF-16和Unicode編碼,一般不會涉及到。 private boolean hasSurrogates = false; // 如果涉及到代理(即涉及到UTF-16和Unicode編碼),會將所有的分隔符轉(zhuǎn)換成碼點值保存到int數(shù)組中 private int[] delimiterCodePoints;
StringTokenizer 的構(gòu)造方法
1、StringTokenizer(String str)只有一個入?yún)⒌臉?gòu)造函數(shù)。
// 單個參數(shù)的構(gòu)造函數(shù),參數(shù)為需要被解析的字符串
public StringTokenizer(String str) {
// 調(diào)用三個參數(shù)的構(gòu)造方法:
// 1、需要被解析的字符串;
// 2、Java默認(rèn)的分隔符,包括空格、制表符、換行符、回車符、\f;
// 3、指示是否將分隔符作為令牌返回的標(biāo)志。false表示分隔符本身不會被視為令牌
this(str, " \t\n\r\f", false);
}2、StringTokenizer(String str, String delim)兩個入?yún)⒌臉?gòu)造函數(shù)
// 兩個參數(shù)的構(gòu)造方法,str:需要被解析的字符串 delim:分隔符字符串,每一個字符都是一個分隔符
public StringTokenizer(String str, String delim) {
// 1、需要被解析的字符串;
// 2、使用指定的字符作為分割符
// 3、指示是否將分隔符作為令牌返回的標(biāo)志。false表示分隔符本身不會被視為令牌
this(str, delim, false);
}3、StringTokenizer(String str, String delim, boolean returnDelims)三個入?yún)⒌臉?gòu)造函數(shù)
public StringTokenizer(String str, String delim, boolean returnDelims) {
// 當(dāng)前位置設(shè)為0,即索引下標(biāo)為0
currentPosition = 0;
// 下個要處理的位置
newPosition = -1;
// 分隔符是否改變的表示,true表示分隔符發(fā)生改變,false表示分隔符沒發(fā)生改變,默認(rèn)為false
delimsChanged = false;
// 要分割的字符串
this.str = str;
// 最大位置,即被分割字符串的長度
maxPosition = str.length();
// 設(shè)置分隔符,字符串中的每個字符都是一個分隔符
delimiters = delim;
// 指示是否將分隔符作為令牌返回的標(biāo)志。
retDelims = returnDelims;
// 設(shè)置分割符中ASCII碼值最大字符
setMaxDelimCodePoint();
}StringTokenizer public修飾的方法
hasMoreTokens() 判斷是否被分割字符串中是否有更多可用的標(biāo)記
注意:該方法為public修飾的方法。
1、返回true,表示后續(xù)調(diào)用nextToken()將成功返回一個token(即分割好的字符串)。
2、返回false,表示后續(xù)調(diào)用nextToken()將會拋出異常:NoSuchElementException
// 如果retDelims為false(不將分隔符作為令牌返回的標(biāo)志),判斷當(dāng)前位置及當(dāng)前位置之后是否還有非分隔符的字符
// 如果retDelims為true(將分隔符作為令牌返回的標(biāo)志),判斷當(dāng)前位置是否小于被分割字符串的長度
public boolean hasMoreTokens() {
/*
* Temporarily store this position and use it in the following
* nextToken() method only if the delimiters haven't been changed in
* that nextToken() invocation.
*
* 臨時存儲此位置,并僅在nextToken()調(diào)用中分隔符未更改時在以下nextToken()方法中使用它。
*/
// 如果retDelims為false(不將分隔符作為令牌返回的標(biāo)志),則返回當(dāng)前位置或當(dāng)前位置之后第一個非分隔符的字符索引
// 如果retDelims為true(將分隔符作為令牌返回的標(biāo)志),返回當(dāng)前位置字符的索引
newPosition = skipDelimiters(currentPosition);
// 當(dāng)前位置小于被分割字符串的長度
return (newPosition < maxPosition);
}nextToken()獲取下一個根據(jù)分隔符拆分的字符串
注意:該方法為public關(guān)鍵字修飾的方法
// 獲取下一個根據(jù)分隔符拆分的字符串
public String nextToken() {
? ? /*
? ? ?* If next position already computed in hasMoreElements() and
? ? ?* delimiters have changed between the computation and this invocation,
? ? ?* then use the computed value.
? ? ?* 如果下一個位置已經(jīng)在hasMoreElements()中計算過,并且分隔符在計算和調(diào)用之間發(fā)生了變化,則使用計算值。
? ? ?*/
? ? // 當(dāng)下一個要處理的字符索引 >= 0 并且 分隔符未發(fā)生改變時,將下一個要處理的字符索引 賦值給 當(dāng)前位置(當(dāng)前要處理的字符索引)
? ? // 否則重新計算下一個要處理的字符索引
? ? currentPosition = (newPosition >= 0 && !delimsChanged) ?
? ? ? ? newPosition : skipDelimiters(currentPosition);
? ? /* Reset these anyway */
? ? // 將分隔符是否改變的標(biāo)志設(shè)置為false,表示分隔符不再變化
? ? delimsChanged = false;
? ? // 重新將下一個要處理的字符索引設(shè)置為-1
? ? newPosition = -1;
? ? // 如果當(dāng)前位置 >= 最大位置,拋出異常
? ? if (currentPosition >= maxPosition)
? ? ? ? throw new NoSuchElementException();
? ? // 將當(dāng)前位置設(shè)置為截取字符串的開始下標(biāo)
? ? int start = currentPosition;
? ? // 獲取下一個分隔符的索引。并且currentPosition(當(dāng)前位置)變?yōu)榉指舴谖恢玫乃饕?
? ? currentPosition = scanToken(currentPosition);
? ? // 截取字符串,從第一個非分隔符的索引開始,到下一個分隔符的索引結(jié)束。
? ? return str.substring(start, currentPosition);
}nextToken(String delim)根據(jù)新的分隔符獲取下一個被拆分出來的字符串
注意:該方法為public修飾的方法
// 根據(jù)新的分隔符獲取下一個被拆分出來的字符串
public String nextToken(String delim) {
? ? // 設(shè)置分隔符,字符串中的每個字符都是一個分隔符
? ? delimiters = delim;
? ? /* delimiter string specified, so set the appropriate flag.
? ? * 創(chuàng)建對象后重新設(shè)置分隔符字符串,需要將此標(biāo)志設(shè)置為true。 */
? ? delimsChanged = true;
? ? // 需改分隔符字符串后需要重新設(shè)置設(shè)置maxDelimCodePoint(分隔符中的最高字符,即ASCII碼值最大的的字符)
? ? setMaxDelimCodePoint();
? ? // ?根據(jù)分隔符獲取下一個拆分出來的字符串
? ? return nextToken();
}countTokens()獲取被分割的字符串中還能拆分出幾個字符串。
注意:該方法為public修飾的方法,隨這nextToken()方法的調(diào)用,該方法返回值會發(fā)生變化。
// 獲取被分割的字符串中還能拆分出幾個字符串。隨這nextToken()方法的調(diào)用,該方法返回值會發(fā)生變化
public int countTokens() {
int count = 0;
// currentPosition為成員變量,所以會隨著其他方法的調(diào)用發(fā)生變化,因此該方法的返回值會發(fā)生變化
int currpos = currentPosition;
// 當(dāng)前位置字符 < 被分割字符串長度
while (currpos < maxPosition) {
// 獲取當(dāng)前位置或當(dāng)前位置之后第一個非分隔符的字符索引
currpos = skipDelimiters(currpos);
// 如果 當(dāng)前位置 >= 被分割字符串長度 則跳出循環(huán)
if (currpos >= maxPosition)
break;
// 獲取下一個分隔符的索引
currpos = scanToken(currpos);
count++;
}
return count;
}StringTokenizer private修飾的方法
setMaxDelimCodePoint()設(shè)置分隔符中的最高字符,即ASCII碼值最大的的字符。
注意:該方法為private修飾的方法。
// 設(shè)置maxDelimCodePoint的值為分隔符中的最高字符,即ASCII碼值最大的的字符。
private void setMaxDelimCodePoint() {
? ? // 如果分隔符為null,
? ? if (delimiters == null) {
? ? ? ? maxDelimCodePoint = 0;
? ? ? ? return;
? ? }
? ? int m = 0;
? ? int c;
? ? int count = 0;
? ? // Character.charCount(c) 如果c大于等于 Unicode最小補充碼點 返回2,否則返回1
? ? for (int i = 0; i < delimiters.length(); i += Character.charCount(c)) {
? ? ? ? // delimiters分隔符字符串中下標(biāo)為i的字符,使用int接收,返回的是ASCII值
? ? ? ? c = delimiters.charAt(i);
? ? ? ? // 如果 c >= Unicode編碼的最小高代理 并且 c <= Unicode編碼的最大低代理。與UTF-16相關(guān)。
? ? ? ? if (c >= Character.MIN_HIGH_SURROGATE && c <= Character.MAX_LOW_SURROGATE) {
? ? ? ? ? ? // 獲取分隔符字符串 下標(biāo)為i處的字符的Unicode碼點值
? ? ? ? ? ? c = delimiters.codePointAt(i);
? ? ? ? ? ? // 將是否使用代理設(shè)置為true
? ? ? ? ? ? hasSurrogates = true;
? ? ? ? }
? ? ? ? // 比較每個分隔符的ASCII值,將最大ASCII值賦值給m
? ? ? ? if (m < c)
? ? ? ? ? ? m = c;
? ? ? ? // count表示
? ? ? ? count++;
? ? }
? ? // 將最大ASCII值賦值給maxDelimCodePoint
? ? maxDelimCodePoint = m;
? ? // 如果有代理
? ? if (hasSurrogates) {
? ? ? ? // 如果涉及到UTF-16和Unicode編碼,將所有分隔符轉(zhuǎn)換成 Unicode碼點值
? ? ? ? delimiterCodePoints = new int[count];
? ? ? ? for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
? ? ? ? ? ? c = delimiters.codePointAt(j);
? ? ? ? ? ? delimiterCodePoints[i] = c;
? ? ? ? }
? ? }
}skipDelimiters()獲取下一個要處理字符的索引
注意:該方法為private修飾的方法
// 如果retDelims為false(不將分隔符作為令牌返回的標(biāo)志),則返回當(dāng)前位置或當(dāng)前位置之后第一個非分隔符的字符索引
// 如果retDelims為true(將分隔符作為令牌返回的標(biāo)志),返回當(dāng)前位置字符的索引
private int skipDelimiters(int startPos) {
? ? // 分隔符字符串非空校驗
? ? if (delimiters == null)
? ? ? ? throw new NullPointerException();
? ? // 記錄字符串下標(biāo)位置,即當(dāng)前判斷的位置
? ? int position = startPos;
? ? // retDelims 一般設(shè)置為false,表示不將分隔符作為令牌返回的標(biāo)志。
? ? while (!retDelims && position < maxPosition) {
? ? ? ? // hasSurrogates默認(rèn)為false,表示沒有代理,即不涉及UTF-16和Unicode編碼
? ? ? ? if (!hasSurrogates) {
? ? ? ? ? ? // 從被分割字符串str中獲取當(dāng)前位置的字符
? ? ? ? ? ? char c = str.charAt(position);
? ? ? ? ? ? // 如果 當(dāng)前位置的字符 大于 分隔符中的最大字符 或者 分隔符字符串中沒有當(dāng)前字符
? ? ? ? ? ? if ((c > maxDelimCodePoint) || (delimiters.indexOf(c) < 0))
? ? ? ? ? ? ? ? // 跳出循環(huán)
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? // 當(dāng)前位置 +1
? ? ? ? ? ? position++;
? ? ? ? } else {
? ? ? ? ? ? // 存在代理(涉及UTF-16和Unicode編碼),獲取當(dāng)前位置字符的Unicode碼點值
? ? ? ? ? ? int c = str.codePointAt(position);
? ? ? ? ? ? // 如果當(dāng)前位置的字符碼點值大于分隔符中的最大字符 或者 當(dāng)前碼點至對應(yīng)的字符不是分隔符
? ? ? ? ? ? if ((c > maxDelimCodePoint) || !isDelimiter(c)) {
? ? ? ? ? ? ? ? // 跳出本次循環(huán)
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? // 如果c大于等于 Unicode最小補充碼點 當(dāng)前位置+2,否則,當(dāng)前位置+1
? ? ? ? ? ? position += Character.charCount(c);
? ? ? ? }
? ? }
? ? return position;
}isDelimiter()判斷碼點值對應(yīng)的字符是不是分隔符
注意:該方法為private修飾的方法
// 判斷碼點值對應(yīng)的字符是不是分隔符,返回true表示當(dāng)前碼點值是一個分隔符,返回false表示當(dāng)前的碼點值不是分隔符的碼點值
private boolean isDelimiter(int codePoint) {
// 涉及到代理(即涉及到UTF-16和Unicode編碼),從分隔符成碼點值數(shù)組中遍歷
for (int delimiterCodePoint : delimiterCodePoints) {
// 如果分隔符成碼點值數(shù)組中的某一個值等于當(dāng)前碼點值
if (delimiterCodePoint == codePoint) {
// 返回true
return true;
}
}
// 返回false
return false;
}scanToken(int startPos)獲取下一個分隔符的索引
注意:該方法為private修飾的方法
// 從startPos跳過并返回遇到的下一個分隔符字符的索引,如果沒有找到這樣的分隔符,則返回maxPosition。
private int scanToken(int startPos) {
int position = startPos;
// 當(dāng)要操作的字符索引小于被分割字符串的長度
while (position < maxPosition) {
// 當(dāng)不包含代理,即不涉及到UTF-16和Unicode編碼。
if (!hasSurrogates) {
// 獲取當(dāng)前索引位置的字符
char c = str.charAt(position);
// 當(dāng)前字符 <= 分隔符最大字符 并且 當(dāng)前字符是一個分隔符。找到分隔符時推出
if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
// 退出循環(huán)
break;
// 當(dāng)前索引位置+1
position++;
} else {
// 獲取當(dāng)前索引位置對應(yīng)的字符的Unicode碼值
int c = str.codePointAt(position);
// 當(dāng)前字符 <= 分隔符最大字符 并且 當(dāng)前字符是一個分隔符。找到分隔符時推出
if ((c <= maxDelimCodePoint) && isDelimiter(c))
break;
// 涉及到Unicode編碼,需要判斷當(dāng)前字符是占一個位置還是兩個位置
position += Character.charCount(c);
}
}
// 需要將分隔符作為令牌返回的標(biāo)志,并且 當(dāng)前位置與起始位置一直
if (retDelims && (startPos == position)) {
// 當(dāng)不包含代理,即不涉及到UTF-16和Unicode編碼。
if (!hasSurrogates) {
char c = str.charAt(position);
// 當(dāng)前字符 <= 分隔符最大字符 并且 當(dāng)前字符是一個分隔符。
if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
position++;
} else {
int c = str.codePointAt(position);
// 當(dāng)前字符 <= 分隔符最大字符 并且 當(dāng)前字符是一個分隔符。
if ((c <= maxDelimCodePoint) && isDelimiter(c))
// // 涉及到Unicode編碼,需要判斷當(dāng)前字符是占一個位置還是兩個位置
position += Character.charCount(c);
}
}
// 返回分隔符的索引值
return position;
}StringTokenizer 類的使用
1、可以使用以下方式創(chuàng)建一個spring容器
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext();
// 設(shè)置配置文件路徑,多個位置使用逗號、分號、空格、制表符、換行 五種方式分割。
classPathXmlApplicationContext.setConfigLocation("classpath*:/*.xml");
classPathXmlApplicationContext.refresh();
}2、main方法中創(chuàng)建ClassPathXmlApplicationContext對象后會調(diào)用setConfigLocation(String location)方法。
該方法是AbstractRefreshableConfigApplicationContext類中的方法。源代碼如下:
public void setConfigLocation(String location) {
// 將傳入的字符串,根據(jù)逗號、分號、空格、制表符、換行 五種字符拆分成數(shù)組
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}該方法中的CONFIG_LOCATION_DELIMITERS是ConfigurableApplicationContext接口中定義的常量。
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
3、setConfigLocation(String location)方法會調(diào)用StringUtils中的方法。源代碼如下:
// 根據(jù) delimiters字符串中的字符作為分隔符,將str拆分成數(shù)組
public static String[] tokenizeToStringArray(@Nullable String str, String delimiters) {
return tokenizeToStringArray(str, delimiters, true, true);
}4、調(diào)用StringUtils中重載的setConfigLocation方法,源代碼如下:
1)該方法中調(diào)用了StringTokenizer類中的hasMoreTokens()方法作為循環(huán)條件。
2)該方法中調(diào)用StringTokenizer類中的nextToken()方法獲取下一個根據(jù)分隔符拆分的字符串。
通過這兩個方法,將設(shè)置配置文件的字符串根據(jù)指定的分隔符拆分。
// str 要處理的字符串
// delimiters 分隔符,每個字符都是一個分隔符
// trimTokens 拆分出來的字符串是否要去掉首尾的空格。true表示去掉
// ignoreEmptyTokens 是否忽略空字符串。true表示忽略
public static String[] tokenizeToStringArray(
?? ??? ?@Nullable String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
?? ?if (str == null) {
?? ??? ?return EMPTY_STRING_ARRAY;
?? ?}
?? ?// 將要操作的字符串和分隔符字符串設(shè)置到StringTokenizer對象中
?? ?StringTokenizer st = new StringTokenizer(str, delimiters);
?? ?List<String> tokens = new ArrayList<>();
?? ?while (st.hasMoreTokens()) {
?? ??? ?String token = st.nextToken();
?? ??? ?if (trimTokens) {
?? ??? ??? ?token = token.trim();
?? ??? ?}
?? ??? ?if (!ignoreEmptyTokens || token.length() > 0) {
?? ??? ??? ?tokens.add(token);
?? ??? ?}
?? ?}
?? ?// List集合轉(zhuǎn)數(shù)組
?? ?return toStringArray(tokens);
}5、直接使用ClassPathXmlApplicationContext(String configLocation)有參構(gòu)造,直接設(shè)置了配置文件路徑,拆分方式與無參構(gòu)造不同。
到此這篇關(guān)于Java StringTokenizer分隔符拆分字符串的文章就介紹到這了,更多相關(guān)Java StringTokenizer拆分字符串內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Security系列教程之會話管理處理會話過期問題
會話過期,是指當(dāng)用戶登錄網(wǎng)站后,較長一段時間沒有與服務(wù)器進(jìn)行交互,將會導(dǎo)致服務(wù)器上的用戶會話數(shù)據(jù)(即session)被銷毀。這篇文章主要介紹了Spring Security系列教程之會話管理處理會話過期問題,需要的朋友可以參考下2021-10-10
SpringBoot整合Mybatis簡單實現(xiàn)增刪改查
這篇文章主要介紹了SpringBoot整合Mybatis簡單實現(xiàn)增刪改查,文章為圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08
Java之SpringBoot集成ActiveMQ消息中間件案例講解
這篇文章主要介紹了Java之SpringBoot集成ActiveMQ消息中間件案例講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
tk.mybatis實現(xiàn)uuid主鍵生成的示例代碼
本文主要介紹了tk.mybatis實現(xiàn)uuid主鍵生成的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12
springboot+Quartz實現(xiàn)任務(wù)調(diào)度的示例代碼
本篇文章主要介紹了springboot + Quartz 實現(xiàn)任務(wù)調(diào)度的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02

