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