java:java.util.StringTokenizer实现字符串切割
java:java.util.StringTokenizer实现字符串切割
1 前言
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);
}
又如定时任务框架Quartz中,cron表达式类CronExpression,其中的buildExpression方法是为了处理cron表达式的,cron表达式有7个子表达式,空格隔开,cron表达式字符串的切割也使用到了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);}
}
2 使用
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("字符串数组:" + strs);}}
执行结果:
切割字符串:【你 好 吗 我是 你的 朋友 】;分隔符:【 】。
切割:【你】
切割:【好】
切割:【吗】
切割:【我是】
切割:【你的】
切割:【朋友】
字符串数组:[你, 好, 我是, 你的, 朋友]
源码片段分析:
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;}}
}
调用setMaxDelimCodePoint()方法,源码可知,切割时设置int maxDelimCodePoint,是为了优化分隔符的检测(取的是分隔字符串中char的ASCII码值最大的字符的ASCII值,存入maxDelimCodePoint中。在方法int scanToken(int startPos)中,若满足条件(c <= maxDelimCodePoint) && (delimiters.indexOf© >= 0),意即该字符的ASCII码值小于等于最大的maxDelimCodePoint,那么这个字符可能存在于分隔字符串中,再检测delimiters分隔字符串中是否包含该字符,反之,若ASCII码值大于分隔字符串中最大的maxDelimCodePoint,也就是说该字符一定不存在于分隔字符串里,&&直接跳过delimiters.indexOf的检测,也就达到了优化分隔符检测的效果了)。
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方法即跳过分隔字符串,只要某此循环时,该字符包含在分隔字符串里,那么position不再自增,以此时的position值作为实际切割获取字符串的末索引, 因为subString方法是左闭右开的,该值是实际获取字符串的末索引值+1,所以可以截取到完整的不包含分隔符的字符串片段。
skipDelimiters方法类似,即过滤连续包含于分隔字符串中的字符,获取实际需要切割获取的字符串的开始索引值。
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;
}
上述分析可知,只要待切割字符串中的字符,在分隔字符串中出现,那么就会做一次切割(也就是不论分隔字符串中的每个char或字符串片段的顺序,只要连续包含在分隔字符串里,就切割)。
演示如下(注意countTokens()方法不要在循环中和nextToken()一同使用):
public static void print2(String str, String delimiter, boolean isReturnDelims) {StringTokenizer strTokenizer = new StringTokenizer(str, delimiter);System.out.println("总数目:" + strTokenizer.countTokens());int count;String[] strs = new String[count = strTokenizer.countTokens()];// 注意:不要在循环里写 int i = 0; i < strTokenizer.countTokens();// 因为 countTokens方法需要使用currentPosition,而每次执行nextToken方法时,currentPosition会一直往下偏移计算,// 会导致循环中, i < strTokenizer.countTokens();发生改变,这里应该是常量总数目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;
}
执行:
print2("1a2b3c4ca5bc6ba7abc8acbbaba9", "abc", false);
结果如下所示:
总数目:9
[1, 2, 3, 4, 5, 6, 7, 8, 9]
相关文章:
java:java.util.StringTokenizer实现字符串切割
java:java.util.StringTokenizer实现字符串切割 1 前言 java.util工具包提供了字符串切割的工具类StringTokenizer,Spring等常见框架的字符串工具类(如Spring的StringUtils),常见此类使用。 例如Spring的StringUtil…...
IPV6 ND协议--源码解析【根源分析】
ND协议介绍 ND介绍请阅读上一篇文章:IPv6知识 - ND协议【一文通透】11.NDP协议分析与实践_router solicitation报文中不携带source link-layer address-CSDN博客 ND协议定义了5种ICMPv6报文类型,如下表所示: NS/NA报文主要用于地址解析RS/…...
Python学习笔记——存储容器
食用说明:本笔记适用于有一定编程基础的伙伴们。希望有助于各位! 列表 列表类似数组,其中可以包含不同类型的元素,写法如下: list1 [Google, Runoob, 1997, 2000] list2 [1, 2, 3, 4, 5 ] list3 ["a", …...
Android DI框架-Hilt
到底该如何理解<依赖注入> 模版代码:食之无味,弃之可惜 public class MainActivity extends Activity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);TextView mTextView(TextView) findVi…...
基于寄生捕食优化的BP神经网络(分类应用) - 附代码
基于寄生捕食优化的BP神经网络(分类应用) - 附代码 文章目录 基于寄生捕食优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.寄生捕食优化BP神经网络3.1 BP神经网络参数设置3.2 寄生捕食算法应用 4.测试结果…...
【Java常见的几种设计模式】
Java常见的几种设计模式 1. 单例模式(Singleton Pattern)2. 工厂模式(Factory pattern)3. 抽象工厂模式(Abstract Factory Pattern)4. 建造者模式(Builder Pattern)5. 原型模式&…...
jupyter崩溃进不去,报错module ‘mistune‘ has no attribute ‘BlockGrammar‘
是python包引起的问题 [E 2023-10-14 08:40:25.414 ServerApp] Uncaught exception GET /api/nbconvert?1697244025327 (127.0.0.1) HTTPServerRequest(protocol‘http’, host‘localhost:8090’, method‘GET’, uri‘/api/nbconvert?1697244025327’, version‘HTTP/1.1’…...
windows terminal鼠标右键打开
如果在官网上下载的是zip文件的 需要在注册表修改鼠标右键才能出来 注册表修改如下: 1.先windowsR,在命令框中输入regedit 打开注册表 2.在路径’计算机\HKEY_CLASSES_ROOT\directory\background\shell’下新建一个wt,wt下新建commond 这里…...
HTML5播放 M3U8的hls流地址
在HTML5页面上播放M3U8的hls流地址 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>视频播放</title> <script src"https://cdn.jsdelivr.net/npm/hls.jslatest"></script> &…...
leetcode:101.对称二叉树
借用二叉树是否相同的代码改动左右孩子相等对应关系,即为是否对称。 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/bool isSameTree(struct TreeNode* p, struct Tr…...
UI自动化的适用场景,怎么做?
经常有人会问,什么样的项目才适合进行UI自动化测试呢?UI自动化测试相当于模拟手工测试,通过程序去操作页面上的控件。而在实际测试过程中,经常会遇到无法找到控件,或者因控件定义变更而带来的维护成本等问题。 哪些场…...
SpringFramewrok (1)
1、框架的概念与理解 在现实生活中,框架可以比喻为我们搭建房子的框架。 在框架的基础上,我们可以专注于我们自己的工作,而不用在意这些底层工作如何实现。 框架的优点包括以下几点: 1. 提高开发效率:框架提供了许多…...
电商独立站小程序开发方案
随着移动互联网的迅速发展,电商行业也逐渐向小程序平台转移。开发一款电商小程序对于拓展销售渠道、提高用户体验、增加用户忠诚度等方面都有着重要的意义。本文将围绕电商小程序的开发背景、需求分析、技术选型、开发流程、风险控制、商业模式和市场前景等方面进行…...
数据库安全运维是什么意思?数据库安全运维系统用哪家好?
我们大家都直到数据在某些情况下容易丢失或被破坏,攻击者可能通过对数据库进行破坏或勒索等手段获取利益。所以保障数据库安全至关重要。今天我们就来聊聊数据库安全运维是什么意思?数据库安全运维系统用哪家好? 数据库安全运维是什么意思&…...
小程序的console中出现:。。。不在以下 request 合法域名列表中,请参考文档:。。。的报错解决
报错效果: 其实这个报错不代表自己的代码有问题 但是本强迫症研究了一下,按照以下方法关掉就不会显示这个报错了。 点微信开发者工具中的右上角的详情。点本地设置。勾选不校验。。。HTTPS证书。 即可关闭该报错:...
计算机网络基础(三):IPv4编址方式、子网划分、IPv4通信的建立与验证及ICMP协议
**IPv4地址是一个32位长的二进制数。**而这个32位二进制数又通常会表示为4个用点隔开的十进制数。那么,这个32位二进制数要如何通过4个十进制数表示出来呢? 我们在配置IPv4地址时,同时配置的“掩码”又有何用途? 1.IPv4编址方式…...
Error: GlobalConfigUtils setMetaData Fail Cause:java.lang.NullPointerException
文章目录 1、在开发中会出现这样的错误。2、其次,再看其他错误: 1、在开发中会出现这样的错误。 完整错误:Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Error: GlobalConfigUtils setMetaData Fail ! Cause…...
OpenHarmony 应用全局的 UI 状态存储:AppStorage
AppStorage 是应用全局的 UI 状态存储,是和应用的进程绑定的,由 UI 框架在应用程序启动时创建,为应用程序 UI 状态属性提供中央存储。 和 AppStorage 不同的是,LocalStorage 是页面级的,通常应用于页面内的数据共享。而…...
外置告警蜂鸣器使用小坑
告警蜂鸣器调试小坑 昨天调试新产品,由于IMO、MSC组织和IEC标准规定,不能使用带红色指示灯的蜂鸣器,于是更换了个不带灯。然而奇怪的现象出现了两次短响的程序在有的页面正常,有的页面就变成一声了。搞了一天,把各种寄…...
SSO身份验证如何帮助加强密码安全性
单点登录 (SSO) 是一种身份验证服务,可帮助用户使用一组凭据快速安全地访问所有应用程序。在员工需要访问多个应用程序才能完成工作的企业环境中,每次需要访问时都必须为每个应用程序输入登录凭据,这是一个主要的烦恼来…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
