一、前语
不就展示一个富文本吗,有啥难的,至于这么大惊小怪吗,哎,各位老铁,莫慌,先看需求,咱们再一探究竟。
1、大致需求
要求,用户内容修改页面,完成图文混排,1、图片随意方位刺进,并且可长按拖动排序;2、图片拖动完成之后,上下无内容,则需求空出输入方位,有内容,则无需空出;3、内容支撑随意方位刺进;4、以富文本的办法传入后台;5、解析富文本,回显内容。
2、大致作用图
完成这个需求倒不是很难,直接一个RecyclerView就搞定了,无非便是运用ItemTouchHelper,再和RecyclerView绑定之后,在onMove办法里完成Item的方位转化,当然需求处理一些图片和输入框之间的逻辑,这个不是本篇文章的要点,今后再说一块。
作用的话,我又独自的写了一个Demo,和项目中用到的相同,具体作用如下:
获取富文本的办法也是比较的简略,不论文本仍是图片,终究都是存到调集中,咱们直接遍历调集,给图片和文字设置对应的富文本标签即可,具体的特点,比方宽高,颜色大小,能够自行界说,大致如下:
/**
* AUTHOR:AbnerMing
* INTRODUCE:返回富文本数据
*/
fun getRichContent(): String {
val endContent = StringBuffer()
mRichList.forEach {
if (it.isPic == 0) {
//图片
endContent.append("<img src="https://juejin.im/post/7249604020875984955/" + it.image + "https://juejin.im/post/7249604020875984955/"/>")
} else {
//文本
endContent.append("<p>" + it.text + "</p>")
}
}
return endContent.toString()
}
以上的各个环节,不论怎样说,仍是比较的顺利,接下来就到了咱们今天的话题了,富文本咱们是传上去了,可是怎样回显呢?
二、富文本回显剖析
回显有两种状况,榜首种是修改之后,能够保存至草稿,下次再修改时,需求回显;第二种状况是,内容现已发布了,能够再次修改内容。
具体的草稿回显有多种办法,咱们不是运用RecyclerView完成的吗,直接保存列表数据就能够了,能够运用本地或许数据库办法的存储办法,不论运用哪种,完成起来绝非难事,回显的时分也是以调集的办法传入RecyclerView即可。
内容现已发布过的,这才是探究的要点,由于接口返回的是富文本信息,一开端无脑想到的是,富文本信息还得要解析里边的内容,着实麻烦,想着每次发布成功之后在本地存储一份数据,在修改的时分,依据约定好的标识去存储的数据里找,的确能够完成,可是疏忽了这是网络数据,是能够更换设备的,换个设备,数据从哪取呢?哈哈,这种投机取巧的计划,实在是不可取。
那没办法了,解析富文本呗,然后逐次取出图片和内容,再封装成调集,回显到RecyclerView中即可。
三、富文本解析
以下是发布成功后,某个字段的富文本信息,咱们拿到之后,需求回显到修改的页面,也便是自界说的RecyclerView中,老铁们,你们的榜首处理计划是什么?
<p>我是测验内容</p><p>我是测验内容12333</p><img src="https://www.6hu.cc/wp-content/uploads/2023/07/1688880879-7ac3c7b5ce71919.png"/><p>我是测验内容88888</p><p>我是测验内容99999999</p><img src="https://www.6hu.cc/wp-content/uploads/2023/07/1688880873-46016259ac5b247.png"/>
咱们终究需求拿到的数据,如下,只有这样,咱们才干逐个封装到调集,回显到列表中。
我是测验内容
我是测验内容12333
https://www.6hu.cc/wp-content/uploads/2023/07/1688880879-7ac3c7b5ce71919.png
我是测验内容88888
我是测验内容99999999
https://www.6hu.cc/wp-content/uploads/2023/07/1688880873-46016259ac5b247.png
字符串截取呗,我相信这是咱们的榜首直觉,以什么办法截取,才干拿到标签里的内容呢?能够负责任的告知咱们,截取是能够完成的,需求完成的逻辑有点多,我简略的举一个截取的比方:
content = content.replace("<p>", "")
val split = content.split("</p>")
val contentList = arrayListOf<String>()
for (i in split.indices) {
val pContent = split[i]
if (TextUtils.isEmpty(pContent)) {
continue
}
if (pContent.contains("img")) {
//包含了图片
val imgContent = pContent.split("/>")
for (j in imgContent.indices) {
val img = imgContent[j]
if (img.contains("img")) {
//图片,需求再次截取
val index = img.indexOf(""")
val last = img.lastIndexOf(""")
val endImg = img.substring(index + 1, last)//终究的图片内容
contentList.add(endImg)
} else {
//文本内容
contentList.add(img)
}
}
} else {
contentList.add(pContent)
}
}
截取的办法有很多种,可是不论哪一种,你的判断是少不了的,为了取得对应的内容,不得不多级嵌套,不得不一而再再而三的进行截取,尽管完成了,可是其冗余了代码,丢掉了效率,现在仍是仅有两种标签,如果说今后的富文本有多种标签呢?想想都可怕。
有没有一种比较简洁的办法呢?必须有,那便是正则表达式,需求处理两个问题,榜首、正则怎样用?第二,正则表达式怎样写?搞理解这两条之后,获取富文本中想要的内容就很简略了。
四、Kotlin中的正则运用
提到正则,咱就不得不聊聊Java中的正则,这是咱们做Android再熟悉不过的,一般也是最常用的,基本代码如下:
String str = "";//匹配内容
String pattern = "";//正则表达式
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(str);
System.out.println(m.matches());
获取匹配内容的话,取对应的group即可,这个比方太多了,就不独自举了,除了Java中供给的Api之外,在Kotlin傍边,也供给了相关的Api,运用起来也是无比的简略。
在Kotlin中,咱们能够运用Regex这个方针,主要用于搜索字符串或替换正则表达式方针,咱们举几个简略的比方。
1、判定是否包含某个字符串,containsMatchIn
val regex = Regex("Ming")//界说匹配规矩
val matched = regex.containsMatchIn("AbnerMing")//传入内容
print(matched)
输出成果
true
2、匹配方针字符串matches
val regex = """[A-Za-z]+""".toRegex()//只匹配英文字母
val matches1 = regex.matches("abcdABCD")
val matches2 = regex.matches("12345678")
println(matches1)
println(matches2)
输出成果
true
false
3、返回初次呈现指定字符串find
val time = Regex("""\d{4}-\d{1,2}-\d{1,2}""")
val timeValue= time.find("今天是2023-6-28,北京,有雨,请记得带雨伞!")?.value
println(timeValue)
输出成果
2023-6-28
4、返回一切状况呈现方针字符串findAll
val time = Regex("""\d{4}-\d{1,2}-\d{1,2}""")
val timeValue = time.findAll(
"今天是2023-6-28,北京,有雨,请记得带雨伞!" +
"明天是2023-6-29,或许就没有雨了,具体得等到后天2023-6-30日才干知晓!"
)
timeValue.forEach {
println(it.value)
}
输出成果
2023-6-28
2023-6-29
2023-6-30
ok,当然了,里边还有许多办法,比方替换,切割等,这儿就不介绍了,后续有时间补一篇,基本上常用的便是以上的几个办法。
五、富文本运用正则获取内容
一个富文本里的标签有很多个,显然咱们都需求进行获取里边的内容,这儿肯定是要运用findAll这个办法了,可是,咱们该怎样设置标签的正则表达式呢?
咱们知道,富文本中的标签,都是有左右尖括号组成的,比方<p></p>,<a></a>
,当然也有单标签,比方<img/>,<br/>
等,那这就有规律了,无非便是最初<开端,然后是不确定字母,再加上完毕的>就能够了。
1、标签精确匹配
比方有这样一个富文本,咱们要获取一切的<p></p>
标签。
<div>早上好啊</div><p>我是一个阶段</p><a>我是一个链接</a><p>我是另一个一个阶段</p>
咱们的正则表达式就如下:
<p.*?>(.*?)</p>
什么意思呢,便是以<p
最初,</p>
完毕,这个点.是除换行符以外的一切字符,*为匹配0次或多次,?为0次或1次匹配,之所以最初这样写<p.*?>
而不是<p>
,一个重要的原因便是需求匹配到特点或许空格,要不然富文本中带了特点或空格,就无法匹配了,这个需求留意!
基本代码
val content = "<div>早上好啊</div><p>我是一个阶段</p><a>我是一个链接</a><p>我是另一个一个阶段</p>"
val matchResult = Regex("""<p.*?>(.*?)</p>""").findAll(content)
matchResult.forEach {
println(it.value)
}
运转成果
<p>我是一个阶段</p>
<p>我是另一个一个阶段</p>
看到上面的的成果,有的老铁就问了,我要的是内容啊,怎样把标签也返回了,这如同有点不对吧,如果说咱们只需匹配到的字符串,现在是对的,可是想要标签里的内容,那么咱们的正则需求再优化一下,怎样优化呢,便是添加一个开端和完毕的方位,内容的开端方位是”<“完毕方位是”>“,如下图
咱们只需求更改下起始方位即可:
匹配内容
val content = "<div>早上好啊</div><p>我是一个阶段</p><a>我是一个链接</a><p>我是另一个一个阶段</p>"
val matchResult = Regex("""(?<=<p>).*?(?=</p>)""").findAll(content)
matchResult.forEach {
println(it.value)
}
运转成果
我是一个阶段
我是另一个一个阶段
2、一切标签进行匹配
有了标签精确匹配之后,针对富文本里的一切的标签内容匹配,就变得很是简略了,无非便是要把上边案例中的p换成一个不确定字母即可。
匹配内容
val content = "<div>早上好啊</div><p>我是一个阶段</p><a>我是一个链接</a><p>我是另一个一个阶段</p>"
val matchResult = Regex("""(?<=<[A-Za-z]*>).+?(?=</[A-Za-z]*>)""").findAll(content)
matchResult.forEach {
println(it.value)
}
运转成果
早上好啊
我是一个阶段
我是一个链接
我是另一个一个阶段
3、单标签匹配
好像现已满足咱们的需求了,由于富文本中的内容现已拿到了,封装到调集之中,传递到列表中即可,可是,以上的正则好像只针对双标签的,带有单标签就无法满足了,比方,咱们再看下初始咱们要匹配的富文本,以上的正则是匹配不到img标签里的src内容的,怎样搞?
<p>我是测验内容</p><p>我是测验内容12333</p><img src="https://www.6hu.cc/wp-content/uploads/2023/07/1688880879-7ac3c7b5ce71919.png"/><p>我是测验内容88888</p><p>我是测验内容99999999</p><img src="https://www.6hu.cc/wp-content/uploads/2023/07/1688880873-46016259ac5b247.png"/>
很简略,单标签独自处理呗,还能咋弄,多个正则表达式,用或拼接即可,特点值也是这样的获取原则,定位开端和完毕方位,比方以上的img标签,如果要获取到src中的内容,只需求定位开端方位”src=”https://juejin.im/post/7249604020875984955/%E2%80%9C%EF%BC%8C%E5%92%8C%E7%BB%93%E6%9D%9F%E4%BD%8D%E7%BD%AE%E2%80%9D”“即可。
匹配内容
val content =
"<p>我是测验内容</p><p>我是测验内容12333</p><img src="https://juejin.im/post/7249604020875984955/https://www.vipandroid.cn/ming/image/gan.png"/><p>我是测验内容88888</p><p>我是测验内容99999999</p><img src="https://www.6hu.cc/wp-content/uploads/2023/07/1688880873-46016259ac5b247.png"/>"
val matchResult =
Regex("""((?<=<[A-Za-z]*>).+?(?=</[A-Za-z]*>))|((?<=src="https://juejin.im/post/7249604020875984955/).+?(?="))""").findAll(content)
matchResult.forEach {
println(it.value)
}
运转成果
我是测验内容
我是测验内容12333
https://www.6hu.cc/wp-content/uploads/2023/07/1688880879-7ac3c7b5ce71919.png
我是测验内容88888
我是测验内容99999999
https://www.6hu.cc/wp-content/uploads/2023/07/1688880873-46016259ac5b247.png
这不就完事了,简简略单,心心念念的数据就拿到了,拿到富文本标签内容之后,再封装成调集,回显到RcyclerView中就能够了,这不很easy吗,哈哈~
点击草稿,咱们看下作用:
六、总结
在正向的截取思想下,正则表达式无疑是最简略的,富文本,不论是标签匹配仍是内容以及特点,都能够运用正则进行简略的匹配,轻轻松松就能搞定,需求留意的是,不同特点的匹配规矩是不相同的,需求依据特有的状况去剖析。