最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的StringTokenizer實(shí)現(xiàn)字符串切割詳解

 更新時(shí)間:2024年01月31日 10:50:42   作者:小徐也要努力鴨  
這篇文章主要介紹了Java中的StringTokenizer實(shí)現(xiàn)字符串切割詳解,java.util工具包提供了字符串切割的工具類StringTokenizer,Spring等常見框架的字符串工具類(如Spring的StringUtils),需要的朋友可以參考下

前言

java.util工具包提供了字符串切割的工具類StringTokenizer,Spring等常見框架的字符串工具類(如Spring的StringUtils),常見此類使用。

例如Spring的StringUtils下的方法:

public static String[] tokenizeToStringArray(
		@Nullable String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {

	if (str == null) {
		return EMPTY_STRING_ARRAY;
	}

	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);
		}
	}
	return toStringArray(tokens);
}

又如定時(shí)任務(wù)框架Quartz中,cron表達(dá)式類CronExpression,其中的buildExpression方法是為了處理cron表達(dá)式的,cron表達(dá)式有7個(gè)子表達(dá)式,空格隔開,cron表達(dá)式字符串的切割也使用到了StringTokenizer類,方法如下:

protected void buildExpression(String expression) throws ParseException {
    this.expressionParsed = true;
    try {
        if (this.seconds == null) {
            this.seconds = new TreeSet();
        }
        if (this.minutes == null) {
            this.minutes = new TreeSet();
        }
        if (this.hours == null) {
            this.hours = new TreeSet();
        }
        if (this.daysOfMonth == null) {
            this.daysOfMonth = new TreeSet();
        }
        if (this.months == null) {
            this.months = new TreeSet();
        }
        if (this.daysOfWeek == null) {
            this.daysOfWeek = new TreeSet();
        }
        if (this.years == null) {
            this.years = new TreeSet();
        }
        int exprOn = 0;
        for(StringTokenizer exprsTok = new StringTokenizer(expression, " \t", false); exprsTok.hasMoreTokens() && exprOn <= 6; ++exprOn) {
            String expr = exprsTok.nextToken().trim();
            if (exprOn == 3 && expr.indexOf(76) != -1 && expr.length() > 1 && expr.contains(",")) {
                throw new ParseException("Support for specifying 'L' and 'LW' with other days of the month is not implemented", -1);
            }
            if (exprOn == 5 && expr.indexOf(76) != -1 && expr.length() > 1 && expr.contains(",")) {
                throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1);
            }
            if (exprOn == 5 && expr.indexOf(35) != -1 && expr.indexOf(35, expr.indexOf(35) + 1) != -1) {
                throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1);
            }
            StringTokenizer vTok = new StringTokenizer(expr, ",");
            while(vTok.hasMoreTokens()) {
                String v = vTok.nextToken();
                this.storeExpressionVals(0, v, exprOn);
            }
        }
        if (exprOn <= 5) {
            throw new ParseException("Unexpected end of expression.", expression.length());
        } else {
            if (exprOn <= 6) {
                this.storeExpressionVals(0, "*", 6);
            }
            TreeSet<Integer> dow = this.getSet(5);
            TreeSet<Integer> dom = this.getSet(3);
            boolean dayOfMSpec = !dom.contains(NO_SPEC);
            boolean dayOfWSpec = !dow.contains(NO_SPEC);
            if ((!dayOfMSpec || dayOfWSpec) && (!dayOfWSpec || dayOfMSpec)) {
                throw new ParseException("Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", 0);
            }
        }
    } catch (ParseException var8) {
        throw var8;
    } catch (Exception var9) {
        throw new ParseException("Illegal cron expression format (" + var9.toString() + ")", 0);
    }
}

使用方法

import com.google.common.collect.Lists;
import java.util.List;
import java.util.StringTokenizer;
/**
 * @author xiaoxu
 * @date 2023-10-18
 * spring_boot:com.xiaoxu.boot.tokenizer.TestStringTokenizer
 */
public class TestStringTokenizer {
    public static void main(String[] args) {
        print("你 好 嗎\t我是 \t你的\t 朋友 \t", " \t", false);
    }
    public static void print(String str, String delimiter, boolean isReturnDelims) {
        System.out.println("切割字符串:【" + str + "】;" + "分隔符:【" + delimiter + "】。");
        List<String> strs = Lists.newArrayList();
        String s;
        boolean x;
        for (StringTokenizer strToken = new StringTokenizer(str, delimiter, false); strToken.hasMoreTokens(); x = (s != null && strs.add(s))) {
            s = strToken.nextToken();
            System.out.println("切割:【" + s + "】");
            if(s.equals("嗎"))
                s = null;
        }
        System.out.println("字符串?dāng)?shù)組:" + strs);
    }
}

執(zhí)行結(jié)果:

切割字符串:【你 好 嗎    我是     你的     朋友     】;分隔符:【     】。
切割:【你】
切割:【好】
切割:【嗎】
切割:【我是】
切割:【你的】
切割:【朋友】
字符串?dāng)?shù)組:[你, 好, 我是, 你的, 朋友]

源碼片段分析

public StringTokenizer(String str, String delim, boolean returnDelims) {
    currentPosition = 0;
    newPosition = -1;
    delimsChanged = false;
    this.str = str;
    maxPosition = str.length();
    delimiters = delim;
    retDelims = returnDelims;
    setMaxDelimCodePoint();
}
private void setMaxDelimCodePoint() {
    if (delimiters == null) {
        maxDelimCodePoint = 0;
        return;
    }
    int m = 0;
    int c;
    int count = 0;
    for (int i = 0; i < delimiters.length(); i += Character.charCount(c)) {
        c = delimiters.charAt(i);
        if (c >= Character.MIN_HIGH_SURROGATE && c <= Character.MAX_LOW_SURROGATE) {
            c = delimiters.codePointAt(i);
            hasSurrogates = true;
        }
        if (m < c)
            m = c;
        count++;
    }
    maxDelimCodePoint = m;
    if (hasSurrogates) {
        delimiterCodePoints = new int[count];
        for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
            c = delimiters.codePointAt(j);
            delimiterCodePoints[i] = c;
        }
    }
}

調(diào)用setMaxDelimCodePoint()方法,源碼可知,切割時(shí)設(shè)置int maxDelimCodePoint,是為了優(yōu)化分隔符的檢測(cè)(取的是分隔字符串中char的ASCII碼值最大的字符的ASCII值,存入maxDelimCodePoint中。在方法int scanToken(int startPos)中,若滿足條件(c <= maxDelimCodePoint) && (delimiters.indexOf© >= 0),意即該字符的ASCII碼值小于等于最大的maxDelimCodePoint,那么這個(gè)字符可能存在于分隔字符串中,再檢測(cè)delimiters分隔字符串中是否包含該字符,反之,若ASCII碼值大于分隔字符串中最大的maxDelimCodePoint,也就是說(shuō)該字符一定不存在于分隔字符串里,&&直接跳過delimiters.indexOf的檢測(cè),也就達(dá)到了優(yōu)化分隔符檢測(cè)的效果了)。

private int scanToken(int startPos) {
    int position = startPos;
    while (position < maxPosition) {
        if (!hasSurrogates) {
            char c = str.charAt(position);
            if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
                break;
            position++;
        } else {
            int c = str.codePointAt(position);
            if ((c <= maxDelimCodePoint) && isDelimiter(c))
                break;
            position += Character.charCount(c);
        }
    }
    if (retDelims && (startPos == position)) {
        if (!hasSurrogates) {
            char c = str.charAt(position);
            if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
                position++;
        } else {
            int c = str.codePointAt(position);
            if ((c <= maxDelimCodePoint) && isDelimiter(c))
                position += Character.charCount(c);
        }
    }
    return position;
}

scanToken方法即跳過分隔字符串,只要某此循環(huán)時(shí),該字符包含在分隔字符串里,那么position不再自增,以此時(shí)的position值作為實(shí)際切割獲取字符串的末索引, 因?yàn)閟ubString方法是左閉右開的,該值是實(shí)際獲取字符串的末索引值+1,所以可以截取到完整的不包含分隔符的字符串片段。

skipDelimiters方法類似,即過濾連續(xù)包含于分隔字符串中的字符,獲取實(shí)際需要切割獲取的字符串的開始索引值。

private int skipDelimiters(int startPos) {
    if (delimiters == null)
        throw new NullPointerException();
    int position = startPos;
    while (!retDelims && position < maxPosition) {
        if (!hasSurrogates) {
            char c = str.charAt(position);
            if ((c > maxDelimCodePoint) || (delimiters.indexOf(c) < 0))
                break;
            position++;
        } else {
            int c = str.codePointAt(position);
            if ((c > maxDelimCodePoint) || !isDelimiter(c)) {
                break;
            }
            position += Character.charCount(c);
        }
    }
    return position;
}

上述分析可知,只要待切割字符串中的字符,在分隔字符串中出現(xiàn),那么就會(huì)做一次切割(也就是不論分隔字符串中的每個(gè)char或字符串片段的順序,只要連續(xù)包含在分隔字符串里,就切割)。

演示如下(注意countTokens()方法不要在循環(huán)中和nextToken()一同使用):

public static void print2(String str, String delimiter, boolean isReturnDelims) {
    StringTokenizer strTokenizer = new StringTokenizer(str, delimiter);
    System.out.println("總數(shù)目:" + strTokenizer.countTokens());
    int count;
    String[] strs = new String[count = strTokenizer.countTokens()];
    // 注意:不要在循環(huán)里寫 int i = 0; i < strTokenizer.countTokens();
    // 因?yàn)? countTokens方法需要使用currentPosition,而每次執(zhí)行nextToken方法時(shí),currentPosition會(huì)一直往下偏移計(jì)算,
    // 會(huì)導(dǎo)致循環(huán)中, i < strTokenizer.countTokens();發(fā)生改變,這里應(yīng)該是常量總數(shù)目
    for (int i = 0; i < count; i++) {
        String s = strTokenizer.nextToken();
        strs[i] = s;
    }
    System.out.println(Arrays.toString(strs));
}

countTokens源碼如下:

public int countTokens() {
    int count = 0;
    int currpos = currentPosition;
    while (currpos < maxPosition) {
        currpos = skipDelimiters(currpos);
        if (currpos >= maxPosition)
            break;
        currpos = scanToken(currpos);
        count++;
    }
    return count;
}

執(zhí)行:

print2("1a2b3c4ca5bc6ba7abc8acbbaba9", "abc", false);

結(jié)果如下所示:

總數(shù)目:9
[1, 2, 3, 4, 5, 6, 7, 8, 9]

到此這篇關(guān)于Java中的StringTokenizer實(shí)現(xiàn)字符串切割詳解的文章就介紹到這了,更多相關(guān)StringTokenizer字符串切割內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mybatis使用Integer類型查詢可能出現(xiàn)的問題

    mybatis使用Integer類型查詢可能出現(xiàn)的問題

    這篇文章主要介紹了mybatis使用Integer類型查詢可能出現(xiàn)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java Character類對(duì)單個(gè)字符操作原理解析

    Java Character類對(duì)單個(gè)字符操作原理解析

    這篇文章主要介紹了Java Character類對(duì)單個(gè)字符操作原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Springboot整合Swagger2和Swagger3全過程

    Springboot整合Swagger2和Swagger3全過程

    這篇文章主要介紹了Springboot整合Swagger2和Swagger3全過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java高效讀取Excel表格數(shù)據(jù)的詳細(xì)教程

    Java高效讀取Excel表格數(shù)據(jù)的詳細(xì)教程

    在日常的軟件開發(fā)和數(shù)據(jù)處理工作中,我們經(jīng)常需要與各種格式的數(shù)據(jù)文件打交道,其中Excel表格因其直觀性和廣泛應(yīng)用而占據(jù)重要地位,手動(dòng)處理Excel數(shù)據(jù)不僅耗時(shí)耗力,而且極易出錯(cuò),尤其是在面對(duì)海量數(shù)據(jù)時(shí),所以本文介紹了Java高效讀取Excel表格數(shù)據(jù)的詳細(xì)教程
    2025-08-08
  • Java操作Mongodb數(shù)據(jù)庫(kù)實(shí)現(xiàn)數(shù)據(jù)的增刪查改功能示例

    Java操作Mongodb數(shù)據(jù)庫(kù)實(shí)現(xiàn)數(shù)據(jù)的增刪查改功能示例

    這篇文章主要介紹了Java操作Mongodb數(shù)據(jù)庫(kù)實(shí)現(xiàn)數(shù)據(jù)的增刪查改功能,結(jié)合完整實(shí)例形式分析了java針對(duì)MongoDB數(shù)據(jù)庫(kù)的連接、增刪改查等相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • Java老舊Web項(xiàng)目XSS漏洞的解決方案

    Java老舊Web項(xiàng)目XSS漏洞的解決方案

    本文提出通過服務(wù)器/中間件加固快速提升老舊系統(tǒng)安全性的三種方案:部署云/軟件WAF攔截攻擊、配置CSP響應(yīng)頭阻斷XSS執(zhí)行、設(shè)置安全HTTP頭防御點(diǎn)擊劫持等,強(qiáng)調(diào)其為短期緩解措施,需配合編碼修復(fù)實(shí)現(xiàn)根本防護(hù)
    2025-08-08
  • Spring中的bean概念介紹

    Spring中的bean概念介紹

    這篇文章主要介紹了Spring中的bean相關(guān)知識(shí),包括基本概念定義控制反轉(zhuǎn)IOC的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • java集合超詳細(xì)(最新推薦)

    java集合超詳細(xì)(最新推薦)

    在內(nèi)存中申請(qǐng)一塊空間用來(lái)存儲(chǔ)數(shù)據(jù),在Java中集合就是替換掉定長(zhǎng)的數(shù)組的一種引用數(shù)據(jù)類型,本文介紹java集合超詳細(xì)講解,感興趣的朋友一起看看吧
    2024-12-12
  • Java實(shí)現(xiàn)求子數(shù)組和的最大值算法示例

    Java實(shí)現(xiàn)求子數(shù)組和的最大值算法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)求子數(shù)組和的最大值算法,涉及Java數(shù)組遍歷、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下
    2018-02-02
  • 如何解決異步任務(wù)上下文丟失問題

    如何解決異步任務(wù)上下文丟失問題

    在多線程編程中,異步任務(wù)可能會(huì)導(dǎo)致上下文信息丟失,為了解決這個(gè)問題,可以在執(zhí)行異步任務(wù)前,通過自定義TaskDecorator拷貝主線程的上下文至子線程,這樣可以確保上下文在異步執(zhí)行過程中得以保留,將定制的TaskDecorator設(shè)置至線程池,可以有效地解決上下文丟失問題
    2024-09-09

最新評(píng)論

延长县| 明光市| 青神县| 海阳市| 金沙县| 嘉荫县| 巢湖市| 宜城市| 叙永县| 沙坪坝区| 兴安盟| 清徐县| 新昌县| 炎陵县| 揭东县| 新宁县| 思茅市| 丹棱县| 沈丘县| 西华县| 东辽县| 深州市| 连南| 军事| 天津市| 手机| 定南县| 射阳县| 莒南县| 长春市| 玛多县| 长沙县| 育儿| 慈利县| 岫岩| 琼海市| 喀喇沁旗| 宁蒗| 桂阳县| 玉溪市| 莱芜市|