【问题标题】:Android: Highlight <em> tags in SpannableStringAndroid:在 SpannableString 中突出显示 <em> 标签
【发布时间】:2016-12-09 15:11:38
【问题描述】:

我有以下代码:

public static SpannableString getSpannable ( String content )
{
    SpannableString s = new SpannableString ( content );

    Matcher m = Pattern.compile ( "<em>(.*?)</em>" ).matcher ( content );

    while ( m.find () )
    { s.setSpan ( new BackgroundColorSpan ( R.color.colorItalic ), m.start ( 1 ), m.end ( 1 ), 0 ); }

    return s;
}

它获取所有&lt;em&gt;(.*?)&lt;/em&gt; 并根据您各自的位置为第一组(.*?) 设置一个BackgroundColorSpan。

效果很好!但问题是&lt;em&gt; 也是在字符串内容内...设置所有跨度后,如何从SpannableString 中删除&lt;em&gt;

【问题讨论】:

    标签: java android spannablestring


    【解决方案1】:

    使用SpannableStringBuilder 代替SpannableString 并使用replace 方法。

    试试这个代码,

    String content = "Yeah, <em>This</em> is bold.";
    
    SpannableStringBuilder s = new SpannableStringBuilder(content);
    
    String startTag = "<em>";
    int startTagLength = startTag.length();
    String endTag = "</em>";
    int endTagLength = endTag.length();
    Matcher m = Pattern.compile(startTag + "(.*?)" + endTag).matcher(content);
    
    while (m.find()) {
        Log.e(TAG, "" + m.start(1));
        Log.e(TAG, "" + m.end(1));
        s.setSpan(new BackgroundColorSpan(R.color.red), m.start(1), m.end(1), 0);
        s.replace(m.end(1), m.end(1) + endTagLength, "");
        s.replace(m.start(1) - startTagLength, m.start(1), "");
    }
    
    TextView out = (TextView) findViewById(R.id.out);
    out.setText(s);
    

    编辑

    Caique Monteiro Araujo 在 cmets 中提到它不适用于多个标签。原因是字符串长度在第二次迭代中被弄乱了,因为我在 while 循环本身中替换了字符串。

    我很高兴 Caique Monteiro Araujo 找到了解决方法。以下是我的。我使用TreeMap 来存储(开始,结束)对并在另一个循环中替换标签。我不知道这是不是矫枉过正。

    String content = "<em>This</em> is <em>bold</em>.";
    
    SpannableStringBuilder s = new SpannableStringBuilder(content);
    
    String startTag = "<em>";
    int startTagLength = startTag.length();
    String endTag = "</em>";
    int endTagLength = endTag.length();
    Matcher m = Pattern.compile(startTag + "(.*?)" + endTag).matcher(content);
    
    // TreeMap to store the start and end pair
    TreeMap<Integer, Integer> pair = new TreeMap<>();
    while (m.find()) {
    
        // Store the start and end
        pair.put(m.start(1), m.end(1));
        s.setSpan(new BackgroundColorSpan(R.color.red), m.start(1), m.end(1), 0);
    }
    
    // Use descendingMap to reverse the Map
    NavigableMap<Integer, Integer> reversePair = pair.descendingMap();
    
    // Replace the tags starting from the last occurrence to avoid messing the length
    for (Integer key : reversePair.keySet()) {
        Integer end = reversePair.get(key);
        s.replace(end, end + endTagLength, "");
        s.replace(key - startTagLength, key, "");
    }
    
    TextView out = (TextView) findViewById(R.id.out);
    out.setText(s);
    

    【讨论】:

    • 出了点问题,我找不到在哪里...我的代码与您的代码完全相同,它只是替换了第一个匹配项,下一个匹配项的输出是错误的。例如,我有This is a &lt;em&gt;test&lt;/em&gt; to &lt;em&gt;understand&lt;/em&gt; the code.,我有This is test to &lt;em&gt;underd&lt;/em&gt; the.
    • @K Neeraj Lal 我知道为什么会这样,匹配器内的while 条件在将标签替换为“”后不会更新content 长度......所以我不得不使用计数器!我用解决方案回答了我的问题,反正我不知道我是否找到了最好的方法=)
    • @K Neeraj Lal 我看到了你的编辑,但它也没有很好地工作,这是因为现在你解决了长度问题,但你没有更新 setSpan 位置是什么让 BackgroundColorSpan 保持不变替换后在新字符串中的位置错误。
    【解决方案2】:

    我通过@K Neeraj Lal 的帮助找到了解决方案,我非常感激。关键是,他的答案在while 循环中不起作用。因此,在删除字符后,我必须创建一个计数器来更新字符位置。这是必要的,因为Matchercontent 变量相关联。因此,当它替换 s 变量时,它会更改您的长度,但内容变量仍然具有相同的长度(Matcher 链接到的位置)。解决方案代码为:

    public static SpannableStringBuilder getSpannable ( String content )
    {
        SpannableStringBuilder s = new SpannableStringBuilder ( content );
    
        String startAt = "<em>";
        String endAt   = "</em>";
    
        Matcher m = Pattern.compile ( startAt + "(.*?)" + endAt ).matcher ( content );
    
        int counter = 0, length  = startAt.length() + endAt.length();
        int startA, startB, endA, endB;
    
        while ( m.find () )
        {
            startA = m.start()-counter;
            endA   = m.end(1)-counter;
            startB = m.start(1)-counter;
            endB   = m.end()-counter;
    
            s.setSpan ( new BackgroundColorSpan ( R.color.colorItalic ), startB, endA, 0 );
            s.replace ( endA, endB, "" );
            s.replace ( startA, startB, "" );
    
            counter += length;
        }
    
        return s;
    }
    

    无论如何,我不知道这是否是最好的方法。

    【讨论】:

    • 不错的方法。我忘了检查多个标签。也检查我的解决方案。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 2010-12-11
    • 2010-10-16
    • 1970-01-01
    相关资源
    最近更新 更多