既要又要的正则匹配规则

news/2024/5/4 12:45:05/文章来源:https://blog.csdn.net/Agg_bin/article/details/127119613

目录

1 背景

2 浅谈

3 分析

3.1 如何识别成整体块?

3.1.1 正则匹配整体块

3.1.2 “ - ”开头“ - ”结尾

3.1.3 模糊匹配不行,采取精准匹配

3.2 如何作为整体块显示?

3.3 光标不可以中间插入

4 效果展示

5 参考代码


1 背景

        在上面这样一个文本编辑框里,点击Server name时,需要在当前光标处插入真实的Server name,且此Server name需要作为一个整体块,光标不可以在Server name中间插入,同时也需要支持整体删除。

        这里可分解成如下3个需求:

  1. 点击Server name时,需要在当前光标处插入真实的Server name;
  2. Server name需要作为一个整体块,光标不可以在Server name中间插入;
  3. Server name需要支持整体删除。

2 浅谈

        Server name作为一个文本插入到某个位置,这比较好实现,但需要作为整体块不可插入且可整体删除,这实现起来没那么容易。

  • 首先会遇到这样一个问题,如何实现整体块?
  • 其次还需要考虑,怎么实现光标不可移到整体块中间?
  • 以及,如何实现整体删除的逻辑?

3 分析

3.1 如何识别成整体块?

        要识别成整体块,需要精准确定整体块的位置,有两种方式可实现:

  • 其一,利用String的indexOf方法找到index,加上length即可确定其具体位置,但如果同时有多个整体块,这种方式就需要优化;
  • 其二,利用正则规则去匹配,可同时匹配到多个整体块。

3.1.1 正则匹配整体块

        使用正则匹配的方式可以实现,但需要考虑误匹配的问题,比如:直接使用字符串匹配肯定不合适,会直接导致整句话被匹配上。所以常规做法就是加入特殊字符,比如:“@username ”采用正则匹配的前提是——以“@”开头以“ ”结尾。username正则匹配规则和内容提取规则如下:

"[@][^@# \\f\\r\\t\\n]{1,30}[ ]" // username匹配正则规则"(?<=@)[^@# \\f\\r\\t\\n]{1,30}(?=[ ])" // 提取username正则规则

        注:username中不允许使用“@”、“#”和空格“ ”。

3.1.2 “ - ”开头“ - ”结尾

        Server name匹配规则我们采用如下方式:以“ - ”开头以“ - ”结尾。

"( - )[^- \\f\\r\\t\\n]{1,50}( - )" // Server name匹配正则规则"(?<=( - ))[^- \\f\\r\\t\\n]{1,50}(?=( - ))" // 提取Server name正则规则

        我们知道正则规则中的“[^- \\f\\r\\t\\n]{1,50}”表示:匹配上的50个字符中不能包含“-”、“ ”、换页“\f”、回车“\r”、制表“\t”、换行“\n”。

        这就存在一个问题,Server name是有可能包含“-”和“ ”的,要么需要定义好Server name中不允许“-”和“ ”,要么就重新设计正则匹配规则,否则会匹配不上Server name。

        那么去掉“^- ”的约束呢,像下面这种正则规则是否合适?

"( - )[^\\f\\r\\t\\n]{1,50}( - )" // Server name匹配正则规则

        答案是不行的🙅‍♂️,会存在误匹配。只有一个Server name能够精确匹配,但是多个Server name会被识别成一个Server name,因为正则匹配采用的贪婪模式,会一直往后找寻。

 

3.1.3 模糊匹配不行,采取精准匹配

        这里我们采用的是模糊匹配:“[^- \\f\\r\\t\\n]{1,50}”,那么如果采用Server name精准匹配呢?

像下面这种,事实证明可以解决模糊匹配的问题。

"( - )Server name( - )" // Server name匹配正则规则

        这个时候只要我们,根据Server name,动态生成匹配规则即可。

    private const val REGEXP_TAG_SERVER_NAME = "( - )"val pattern = Pattern.compile(REGEXP_TAG_SERVER_NAME + "Server name" +  REGEXP_TAG_SERVER_NAME,Pattern.CASE_INSENSITIVE)val matcher = pattern.matcher("待匹配的字符串")if (matcher.find()) {val start = matcher.start()val end = matcher.end()}

3.2 如何作为整体块显示?

        整块显示,实现光标不可移到整体块中间,这里Span可解决问题。万物皆Span,如果你还没使用过Span,那可以去了解下了。

    fun function(){val ssb = SpannableStringBuilder("Hey @username , welcome to - agg group - !");val what = UnEditableSpan(" - agg group - ", "", "", "")ssb.setSpan(what, 27, 42, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)}// 自定义EditText构造中调用setEditableFactory(NoCopySpanEditableFactory(SelectionSpanWatcher(UnEditableSpan::class)))

        顺带一提,@username这种紫色高亮显示,他们实现如出一辙,增加下面一条setSpan即可: 

    ssb.setSpan(ForegroundColorSpan(Color.parseColor("#B5ABFF")),27,42,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

3.3 光标不可以中间插入

class SelectionSpanWatcher<T : Any>(private val kClass: KClass<T>) : SpanWatcherAdapter() {private var selStart = 0private var selEnd = 0override fun onSpanChanged(text: Spannable,what: Any,ostart: Int,oend: Int,nstart: Int,nend: Int) {if (what === Selection.SELECTION_END && selEnd != nstart) {selEnd = nstarttext.getSpans(nstart, nend, kClass.java).firstOrNull()?.run {val spanStart = text.getSpanStart(this)val spanEnd = text.getSpanEnd(this)val index =if (Math.abs(selEnd - spanEnd) > Math.abs(selEnd - spanStart)) spanStart else spanEndSelection.setSelection(text, Selection.getSelectionStart(text), index)}}if (what === Selection.SELECTION_START && selStart != nstart) {selStart = nstarttext.getSpans(nstart, nend, kClass.java).firstOrNull()?.run {val spanStart = text.getSpanStart(this)val spanEnd = text.getSpanEnd(this)val index =if (Math.abs(selStart - spanEnd) > Math.abs(selStart - spanStart)) spanStart else spanEndSelection.setSelection(text, index, Selection.getSelectionEnd(text))}}}}

注:手动输入匹配规则及其内容也可成功匹配,如:手动输入“ - agg group - ”。 

4 效果展示

5 参考代码

    class UnEditableSpan(val showText: String = "", val hashTagName: String = "", val id: String = "", val type: String = "") : MetricAffectingSpan() {override fun updateMeasureState(p: TextPaint) {}override fun updateDrawState(tp: TextPaint) {}}class NoCopySpanEditableFactory(private vararg val spans: NoCopySpan) : Editable.Factory() {override fun newEditable(source: CharSequence): Editable {return SpannableStringBuilder.valueOf(source).apply {spans.forEach {setSpan(it, 0, source.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)}}}}open class SpanWatcherAdapter : SpanWatcher {override fun onSpanChanged(text: Spannable, what: Any, ostart: Int, oend: Int, nstart: Int,nend: Int) {}override fun onSpanRemoved(text: Spannable, what: Any, start: Int, end: Int) {}override fun onSpanAdded(text: Spannable, what: Any, start: Int, end: Int) {}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_16562.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BorderDet:Border Feature for Dense ObjectDetection

原文链接&#xff1a; 概述 密集物体检测依赖于滑动窗口&#xff0c;在图像的规则网格上预测物体&#xff0c;使用点的特征图来生成预测边界框&#xff0c;但由于边界信息不明确导致无法进行准确定位。本文提出了“Border-Align”的操作来从边界点中提取特征来增强点特征。基于…

Jmeter初始学习

Jmeter是一款优秀的开源性能工具&#xff0c;官网文档地址&#xff1a;http://jmeter.apache.org/usermanual/index.html 一、优点 1.开源工具&#xff0c;可扩展性非常好&#xff1b; 2.高可扩展性&#xff0c;用户可自定义调式相关模块代码&#xff1b; 3.精心简单的GUI设…

iOS App更换图标Logo(本地更换)

1.各大购物平台在节假日都是更换App Icon图标 通常有两种方式&#xff1a;1.每换一个新的图标&#xff0c;需要重新上一次AppStore&#xff1b; 2.在项目里预留好未来需要更换的图标&#xff0c;用api触发(或者本地时间判断自动更换) 两种方法各有利弊&#xff0c;第一种 弊&…

「喜迎华诞」手把手教你用微信小程序给头像带上小旗帜

文章目录一、文章前言二、实现原理三、开发步骤四、完整代码五、国庆临近&#xff0c;祝祖国永远繁荣昌盛&#xff01;一、文章前言 2022年是新中国成立73周年&#xff0c;在这个举国欢庆的日子里&#xff0c;让我们给头像上加上小红旗&#xff0c;迎国庆换新颜&#xff0c;一起…

视频倒放怎么制作?快来学会这几个简单的方法

众所周知&#xff0c;如果我们想要让视频更具有观赏性的话&#xff0c;少不了用视频倒放功能来制作视频。不过还是有很多小伙伴不知道视频倒放怎么制作&#xff1f; 下面我就来手把手教你们视频倒放的制作方法&#xff0c;你们快来看看吧&#xff01; 方法一&#xff1a;提词全…

Monaco Editor教程(五): 实现同时多文件编辑,tab切换

背景 上一篇我们讲解了如何设置编辑器的值&#xff0c;获取编辑器的值&#xff0c;以及监听编辑器的内容修改。这些功能对于基础的单文件修改&#xff0c;一次只修改一个文件的业务场景比较友好。但如果是复杂的场景&#xff0c;比如WEB IDE&#xff0c;同时打开一个项目的多个…

聊聊SQL注入

明天是国庆1001,祝大家国庆节快乐!!!这个月还有属于程序员的节日:1024SQL注入问题概述:首先SQL注入是一个非常危险的操作,很可能被一些不怀好意的人钻空导致我们系统出现异常等状况,比如数据库遭到破坏或被入侵。原因:使用JDBC的Statement语句添加SQL语句由于我们的JD…

直播电商开发,源码无加密

随着直播电商的流行&#xff0c;很多企业开始使用商场电商直播系统&#xff0c;该企业使用电商直播系统的优势具体体现在哪里&#xff1f;下面由零七科技小编为您总结企业电商直播系统的优点。 使用电商直播系统的优点&#xff1a; 1、全面展示商品风格和效果。 与在线平台的…

【Django-rest-framework框架】第04回 视图集

目录1. 两个视图基类1.1 GenericAPIview属性和方法1.2 基于APIView写5个接口1.3 基于GenericAPIview写5个接口2. 5个视图扩展类3. 9个视图子类4. 视图集5. 源码分析ViewSetMixin6. 总结7 继承关系画出来,有哪些常用属性或方法写出来 1. 两个视图基类 1.1 GenericAPIview属性和…

【redis】7.1 分布式架构概述(章节介绍)

分布式架构概述 请求业务比较长&#xff08;耗时业务&#xff09;&#xff0c;需要分布式系统。 1. 本章节内容 分布式缓存中间件Redis分布式会话与单点登录分布式搜索引擎Elasticsearch分布式文件系统分布式消息队列分布式锁数据库读写分离与分库分表数据库表全局唯一主键i…

迭代器并不全是指针,list的迭代器与vector和string的有什么不一样,让博主告诉你其底层原理!

链表的模拟实现 文章目录链表的模拟实现一、list的基本架构&#x1f916;_list_node基本构架--双向带头循环链表二、list的迭代器--重点&#x1f431;‍&#x1f464;list迭代器的基本架构构造函数--node*封装operator*()--得到值operator!()--跟另一个迭代器进行比较operator(…

xLua热更新(一)xLua基本使用

一、什么是xLua xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力&#xff0c;借助xLua&#xff0c;这些Lua代码可以方便的和C#相互调用。 xLua是用来实现Lua代码与C#代码相互调用的插件。我们可以借助这个插件来实现热更新方案。 那么为什么要选择Lua实现热更新呢&am…

报告分享|数字化转型,从战略到执行报告

报告链接:http://tecdat.cn/?p=28672 如何加速国家、城市、行业、企业数字化进程,激发数字经济新动能。这份报告通过洞察数字化的6大改变、4大载体、4个阶段、20+场景、100+国家/项目案例/数据,全面系统性地阐述了多层次多场景数字化如何落地实施,最终带来经济、社会价值的…

报告分享|2022年企业数字化人才发展白皮书

报告链接:http://tecdat.cn/?p=28670 数字经济时代,企业对数字化人才的需求急剧增长。此报告对数字化人才培养和企业数字化人才发展现状进行梳理和研究,聚焦于金融、零售、能源和制造四个行业,采用定量与定性相结合的研究方法,对数字化人才的发展态势、岗位能力需求、培养…

第八章 常用用类

文章目录8.4 StringBuffer类8.4.1 StringBuffer对象8.4.2 StringBuffer类的常用方法1.append方法2.charAt(int n)和setCharAt(int n, char ch)8.5 Date类与Calendar类8.5.1 Date类8.5.2 Calendar类8.6 日期的格式变化8.6.1 format方法8.6.2 不同区域的星期格式8.7 Math类、BigI…

【算法】【二叉树模块】求一个二叉树“子树“是否包含另一个二叉树的全部拓扑结构

目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过&#xff0c;但是不保证100%的测试用例&#xff0c;如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识&#xff01; 问题介绍 …

三个线程顺序打印ABC?我有十二种做法,彻底掌握多线程同步通信机制

大家好&#xff0c;我是老三&#xff0c;这篇文章分享一道非常不错的题目&#xff1a;三个线程按序打印ABC。 很多读者朋友应该都觉得这道题目不难&#xff0c;这次给大家带来十二种做法&#xff0c;一定有你没有见过的新姿势。 1. synchronizedwaitnotify 说到同步&#xf…

Swift中的内存访问冲突、指针、局部作用域

内存访问冲突&#xff08;Conflicting Access to Memory&#xff09; 1、内存访问冲突会在两个访问满足以下条件时发生&#xff1a; 至少一个是写入操作它们访问的是同一块内存它们的访问时间重叠&#xff08;比如在同一个函数内&#xff09; //无内存访问冲突 func plus(_ n…

PIE-engine 教程 ——利用NDWI加载青海湖三年水域影像和面积计算

这里我们首先画一个自己选择的研究区&#xff0c;用于方便计算NDWI&#xff0c;这里我们将青海湖区域作为我们的研究区&#xff0c;第二步我们就是要设定一个函数&#xff0c;用于在函数中执行循环遍历&#xff0c;这里包括去云和影像筛选过程&#xff0c;最后按照最大值合成&a…

Windows 10 docker 容器添加新端口映射的方法与步骤

在Docker容器已经创建后&#xff0c;需要添加新的端口映射&#xff0c;即对已经存在的Docker容器添加新的端口映射&#xff0c;可以通过以下步骤来添加&#xff0c;即通过修改配置文件的方法。 1、Windows 10 下 Dockers容器的配置文件存在的路径为&#xff1a; 笔者本文是20…