在看booster内联R的时候,看到过滤R$color这种内部类的时候,是通过正则表达式进行过滤的,然后它的匹配规则是:
|
|
我是想匹配到com/xc/lib/R$color
或com/xc/lib/R
形如这种class的名字,第一眼看的时候有点懵,然后通过查看正则表达式的语法时候,发现正则是有规律可循的,先看一张表格:
符号 | 含义 | 示例 |
---|---|---|
. | 匹配任意单个字符(除换行符) | a.b 可匹配 acb、a1b |
\d | 数字 (0-9) | \d{3} 匹配 123 |
\w | 单词字符 (a-z, A-Z, 0-9, _) | \w+ 匹配 abc_123 |
\s | 空白字符(空格、Tab、换行) | Hello\sWorld 匹配 Hello World |
\S | 单个非空白字符 | 任意单个非空格字符都匹配 |
\b 单词边界 \bcat\b 仅匹配 cat,不匹配 catalog | ||
^ | 行首 | ^Hello 仅匹配 Hello 在行首的情况 |
$ | 行尾 | end$ 仅匹配 end 在行尾的情况 |
* | 匹配前一个字符 0 次或多次 | ab*c 可匹配 ac、abc、abbc |
+ | 匹配前一个字符 1 次或多次 | ab+c 仅匹配 abc、abbc,不匹配 ac |
? | 匹配前一个字符 0 次或 1 次 | ab?c 可匹配 ac 或 abc |
{n} | 匹配 n 次 | a{3} 仅匹配 aaa |
{n,} | 至少匹配 n 次 | a{2,} 可匹配 aa、aaa |
{n,m} | 匹配 n 到 m 次 | a{2,4} 可匹配 aa、aaa、aaaa |
[] | 字符集合 | [aeiou] 匹配任意元音字母 |
` | ` | 或(匹配左边或右边) |
() | 分组 | (ab)+ 匹配 ab、abab |
上面".*/R\\\$.*|.*/R\\.*"
可以拆解成两个正则,因为中间用了一个或,分别是.*/R\\\$.*
、.*/R\\.*
,首先来看.*/R\\\$.*
它可以分解成:
字符 | 含义 | 匹配字符 |
---|---|---|
.* | 表示有0次或多次的单个字符 | com/xc/lib |
/R | 直接匹配字符 | /R |
\$ | 这里由于和$有冲突,所以前面加了转义,匹配的是$字符 | $ |
.* | 和开头的匹配一样,表示有0次或多次的单个字符 | color |
所以最终com/xc/lib/R$color 能被匹配到,再来看.*/R\\.* 它可以分解成: |
||
字符 | 含义 | 匹配字符 |
—— | —— | —— |
.* | 表示有0次或多次的单个字符 | com/xc/lib |
/R | 直接匹配字符 | /R |
\.* | 这里由于和.有冲突,所以前面加了转义,匹配的是0次或多次的.字符 | . |
所以最终com/xc/lib/R
也能被匹配到。
更多正则的匹配:
测试用例:
#key_mmkv_migrate_version#
,正则表达式(#[^#]*[^#\\s]+[^#]*#)
,使用
|
|
该正则表达式作用:用于匹配 以 # 开头和结尾的内容,并且内容中至少包含 一个非空白的非 # 字符。 正则解析:
部分 | 含义 |
---|---|
# | 匹配 #(开始) |
[^#]* | 匹配任意多个非 # 的字符(0 次或多次) |
[^#\s]+ | 至少匹配 1 个非 # 和非空格的字符(保证内容不是空的) |
[^#]* | 再次匹配任意多个非 # 的字符(0 次或多次) |
# | 匹配 #(结束) |
(…) | 括号用于捕获匹配内容 |
Matcher#replaceAll方法
|
|
会被替换成如下:
<a type="topic" >#key_mmkv_migrate_version#</a>
正则:
<a[^>]*?((>[\s\S]*?</a>)|(/>))
|
|
将string转化成Regex:
|
|
用于 匹配 HTML 标签(包括自闭合 和 **带内容的 … 形式)。 正则解析:
部分 | 含义 |
---|---|
<a | 匹配 <a(开始的 标签) |
[^>]*? | 非贪婪匹配 内的所有属性(不包括 >) |
`((… ) | (/>))` |
>[\s\S]*? | 情况 ①:匹配 > 后的内容,直到 |
/ > | 情况 ②:匹配 (自闭合标签) |
CharSequence.contains(regex: Regex):
|
|
contains方法表示是否符合这个正则判断。
Regex.find(input: CharSequence, startIndex: Int = 0): MatchResult? Regex.find() 方法用于 查找字符串中第一个匹配的结果,返回 MatchResult?,如果找不到匹配项,则返回 null。 MatchResult.range:表示匹配的索引范围,分别用start和endInclusive来表示范围。 MatchResult.value:表示匹配到的内容
正则:(\\S+)=\"([^\"]+)\"
作用:主要是用来匹配html/xml属性及其值,比如<a type="topic" >#key_mmkv_migrate_version#</a>
能匹配到,它是匹配type="topic"
。
正则解析:
正则部分 | 作用 |
---|---|
(\S+) | 匹配属性名(非空字符 \S,匹配至少一个字符 +) |
= | 匹配等号(固定字符 =) |
"([^"]+)" | 匹配属性值(被双引号 " 包裹,内容不含 “) |
Regex.findAll
|
|
用于获取字符串中所有符合正则的结果,返回的是一个Sequence的MatchResult
|
|
MatchResult.destructured属性 用来提取匹配结果的捕获组,例如上面提取的是type和topic这一组内容。
例如:
|
|
然后通过MatchResult.destructured.toList()方法转成list,就可以获取type和topic内容了。
SpannableStringBuilder使用
在 Android 开发中,SpannableStringBuilder 主要用于富文本(Styled Text),可以让字符串的一部分具有不同的格式,比如 颜色、大小、样式、点击事件、图片等。它比 Html.fromHtml() 性能更好,更适合动态拼接文本。
使用:
|
|
- SpannableStringBuilder(“Hello, Android!”) 创建一个可变的 Spannable 对象。
- setSpan(ForegroundColorSpan(Color.RED), 7, 14, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
- ForegroundColorSpan(Color.RED) → 设置前景色为红色。
- 7, 14 → 应用范围(“Android” 字符的索引)。
- SPAN_EXCLUSIVE_EXCLUSIVE → 该 Span 只作用于当前字符范围,后续文本修改不会继承。
- textView.movementMethod = LinkMovementMethod.getInstance(),设置 TextView 可点击
所以如果想要多个效果,可以添加多个span给SpannableStringBuilder,通过多次调用setSpan方法,然后设置不同的坐标信息。
SpannableStringBuilder.append(),可以追加多个span的样式,如下:
|
|
上面用到了SpannableString,它是实现了CharSequence,是对字符串进行样式的扩展类,然后把它添加到SpannableStringBuilder中。
span中插入图片,通过imageSpan实现:
|
|