You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SpannableString中查找指定子字符串的索引位置

SpannableString 不转换为普通字符串查找子串索引的实现方案

SpannableString 原生实现了 CharSequence 接口,本身支持直接读取内部字符做匹配,无需转换为普通 String 执行查找。以下是两种可直接使用的实现方案:

方案1:自定义轻量匹配方法

直接基于 CharSequence 接口做字符遍历匹配,无额外依赖,性能最优:

// Kotlin 扩展方法实现,可直接对 SpannableString 调用
fun CharSequence.indexOf(
    sub: CharSequence,
    startIndex: Int = 0,
    ignoreCase: Boolean = false
): Int {
    val subLength = sub.length
    if (subLength == 0) return if (startIndex in indices) startIndex else length
    val firstChar = sub[0]
    var currentPos = startIndex
    val maxSearchPos = length - subLength

    while (currentPos <= maxSearchPos) {
        // 匹配首字符
        if (!charEquals(this[currentPos], firstChar, ignoreCase)) {
            currentPos++
            while (currentPos <= maxSearchPos && !charEquals(this[currentPos], firstChar, ignoreCase)) {
                currentPos++
            }
        }
        // 首字符匹配后校验剩余字符
        if (currentPos <= maxSearchPos) {
            var subPos = 1
            var sourcePos = currentPos + 1
            val endPos = currentPos + subLength
            while (sourcePos < endPos && charEquals(this[sourcePos], sub[subPos], ignoreCase)) {
                sourcePos++
                subPos++
            }
            if (sourcePos == endPos) return currentPos
        }
        currentPos++
    }
    return -1
}

private fun charEquals(c1: Char, c2: Char, ignoreCase: Boolean): Boolean {
    return if (ignoreCase) c1.equals(c2, ignoreCase = true) else c1 == c2
}

使用示例:

val formattedSpannable = SpannableString("带自定义格式的测试文本内容")
val targetSub = "测试文本"
val startIndex = formattedSpannable.indexOf(targetSub) // 匹配成功返回起始索引,失败返回-1

方案2:借助系统正则匹配工具实现

如果需要支持正则匹配能力,可直接使用系统Pattern、Matcher工具,原生支持传入CharSequence类型参数:

// Java 实现示例
import java.util.regex.Pattern;
import java.util.regex.Matcher;

SpannableString formattedSpannable = new SpannableString("带自定义格式的测试文本内容");
String targetSub = "测试文本";
// 用Pattern.quote包裹目标子串,避免子串含正则特殊字符时匹配异常
Pattern pattern = Pattern.compile(Pattern.quote(targetSub));
Matcher matcher = pattern.matcher(formattedSpannable);
if (matcher.find()) {
    int startIndex = matcher.start(); // 子串起始索引
    int endIndex = matcher.end(); // 子串结束索引(不含)
}

两种方案均不会触发SpannableString到普通String的转换,匹配逻辑完全不受SpannableString上绑定的样式Span影响,返回的索引结果和普通String的indexOf方法返回结果一致。

内容的提问来源于stack exchange,提问作者Tamzid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 12:24:04