【问题标题】:Replace certain String with Spans without HTML用没有 HTML 的 Spas 替换某些字符串
【发布时间】:2021-02-21 00:47:33
【问题描述】:

我正在尝试用跨度替换某个字符串。

例如我有这个字符串:

String s = "redHello greenWorld";

我想将“红色”替换为:

modifiedText.setSpan(new ForegroundColorSpan(Color.parseColor("#FF0000")), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

和“绿色”:

modifiedText.setSpan(new ForegroundColorSpan(Color.parseColor("#00FF00")), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

所以我用这种方式创建了 modifiedText:

Spannable modifiedText = new SpannableString(s);

如何用没有 HTML 的 Span 替换某个字符串?

【问题讨论】:

  • 您的问题中似乎有执行此操作的代码。要应用跨度,请致电 setSpan()。如果您的问题是“我如何找到startend 的值?”,您可以使用indexOf() 之类的方法找到start,然后根据start 和长度计算end您正在寻找的子字符串。
  • @CommonsWare 这永远行不通,因为我想替换而不仅仅是找到,所以“红色”和“绿色”这两个词不会被删除......
  • 由于 SpannableString 是不可变的,您可以编写一个返回新字符串的函数(遍历字符串,如果您发现“红色”或“绿色”,则将跨度设置为输出)(我希望我理解你的问题正确)
  • @KH241 这就是问题所在:如何将不是字符串的内容附加到字符串?
  • 但是你不能只计算位置,去掉“红色”和“绿色”然后设置跨度吗?

标签: java android android-spannable


【解决方案1】:

既然你问了关于删减的问题——我希望这就是你的意思(新代码)

//setup
String text = "redHello greenWorld redTest";
List<String> colors = new ArrayList<>();
colors.add("red");
colors.add("green");

//finding the positions
List<Integer> pos = new ArrayList<>();
List<String> colorPositions = new ArrayList<>();
for (String toFind: colors) {
    Pattern word = Pattern.compile(toFind);
    Matcher match = word.matcher(text);
    while (match.find()) {
       pos.add(match.start());
       colorPositions.add(toFind);
    }
}

//replacing
for (String element : colors) {
    text = text.replace(element, "");
}

现在你需要对列表进行排序

//really inefficient sorting
boolean sorted = false;
Integer temp_pos;
String temp_color;
Integer[] sorted_pos = pos.toArray(Integer[]::new);
String[] sorted_color = colorPositions.toArray(String[]::new);
while(!sorted) {
    sorted = true;
    for (int i = 0; i < sorted_pos.length - 1; i++) {
        if (sorted_pos[i] > sorted_pos[i + 1]) {
            temp_pos = sorted_pos[i];
            temp_color = sorted_color[i];
            sorted_pos[i] = sorted_pos[i + 1];
            sorted_color[i] = sorted_color[i + 1];
            sorted_pos[i + 1] = temp_pos;
            sorted_color[i + 1] = temp_color;
            sorted = false;
        }
    }
}

并减去“红色”和“绿色”

//subtracting
for (int i = 1; i < sorted_pos.length; i++) {
    for (int j = i; j < sorted_pos.length; j++) {
        sorted_pos[j] -= sorted_color[i - 1].length();
    }
}

最终结果现在包含 [0, 6, 12],跨度的起始索引 - 现在您只需要遍历输出并设置跨度(跨度的颜色在 sorted_color 中)

【讨论】:

  • 感谢您的代码,@KH241。唯一的问题是,它只有在只有一个“绿色”和“红色”要剪掉时才有效。但是如果有多个,那就有问题了......你可以在这里看到我对字节中多种颜色的完整尝试:pastebin.com/Wvkm9nhQ
  • 我更新了代码 - 您需要弄清楚一两件事,但基本信息在我的回答中。
  • 感谢您的代码。它真的更容易理解,而且非常干净。但是仍然存在一个问题:您将干净的 String 传递给 StringBuilder 构造函数。根据 List pos,应该从位置 9 开始设置绿色。但是由于字符串现在是干净的并且字符串“red”和“green”已经被剪掉,绿色不再需要从位置 9 开始设置,而是从位置 6 开始。我不知道如何计算另外...
  • 伙计,我告诉过你,你需要排序和减去。如果排序部分太难,你应该真正学习你的基础知识和/或谷歌技能。无论如何,我添加了两个部分。现在一切都应该正常了。
  • 不,pos 应该是 [0, 12, 6] 但你的代码 pos 仍然是 [0, 20, 9]...不过,谢谢你的帮助。接受的答案!
【解决方案2】:

SpannableString 不会拆分(子串)给定的String。它只是使用开始和结束索引更改给定范围的属性。如果您想更改String 某些部分的颜色,则不需要子字符串(或剪切)。只需对要更改的部分使用开始和结束索引,其余部分将保持不变(原始)。在您的情况下,根据您的问题,您想更改红色和绿色单词的颜色,因此只需使用 2 个 setSpan 方法,这些单词的开始和结束索引为。

String s = "redHello greenWorld";
SpannableString modifiedText = new SpannableString(s);

//Change the color for 'red' word
modifiedText.setSpan(new ForegroundColorSpan(Color.parseColor("#FF0000")), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

//Change the color for 'green' word
modifiedText.setSpan(new ForegroundColorSpan(Color.parseColor("#00FF00")), 9, 14, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

尽管它是SpannableString,但它仍然是String,因此如果您想将View 设置为Text,您可以像使用String 一样使用它。例如,如果您想将 String 设置为您的 TextView,请使用 setText() 方法和您的 SpannableString

textView.setText(modifiedText);

【讨论】:

  • 字符串“red”和“green”不会被剪掉。我想用空字符串替换它们。
  • 我真的不明白你想要什么。你的字符串是“Hello Word”,你想要红色的 Hello 和绿色的 Word?
  • 我想用绿色替换“green”字符串,用红色替换“red”字符串。这意味着:剪掉字符串“green”和“red”,而是将整个字符串设置为从先前写入“green”或“red”的位置开始的适当颜色。
猜你喜欢
  • 2015-09-16
  • 2018-08-23
  • 2023-03-04
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
  • 1970-01-01
相关资源
最近更新 更多