Android: 突出显示 SpannableString 中的 <em> 个标签
Android: Highlight <em> tags in SpannableString
我有以下代码:
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;
}
它获取所有 <em>(.*?)</em>
并根据您各自的位置将 BackgroundColorSpan 设置为第一组 (.*?)
。
效果很好!但问题是 <em>
也在字符串内容中...设置所有跨度后,如何从 SpannableString
中删除 <em>
?
代替SpannableString
使用SpannableStringBuilder
并使用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's 在评论中提到它不适用于多个标签。这样做的原因是字符串长度在第二次迭代中变得混乱,因为我在 while 循环本身中替换了字符串。
我很高兴 Caique Monteiro Araujo 找到了解决方法。以下是我的。我使用 TreeMap
来存储 (start, end) 对并在另一个循环中替换标签。不知道这样算不算矫枉过正。
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);
我通过@K Neeraj Lal 的帮助找到了解决方案,对此我深表感谢。关键是,他的回答在 while
循环中不起作用。因此,在删除字符后,我必须创建一个计数器来更新字符位置。这是必要的,因为 Matcher
与 content
变量相关联。因此,当它替换 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;
}
无论如何,我不知道这是不是最好的方法。
我有以下代码:
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;
}
它获取所有 <em>(.*?)</em>
并根据您各自的位置将 BackgroundColorSpan 设置为第一组 (.*?)
。
效果很好!但问题是 <em>
也在字符串内容中...设置所有跨度后,如何从 SpannableString
中删除 <em>
?
代替SpannableString
使用SpannableStringBuilder
并使用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's 在评论中提到它不适用于多个标签。这样做的原因是字符串长度在第二次迭代中变得混乱,因为我在 while 循环本身中替换了字符串。
我很高兴 Caique Monteiro Araujo 找到了解决方法。以下是我的。我使用 TreeMap
来存储 (start, end) 对并在另一个循环中替换标签。不知道这样算不算矫枉过正。
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);
我通过@K Neeraj Lal 的帮助找到了解决方案,对此我深表感谢。关键是,他的回答在 while
循环中不起作用。因此,在删除字符后,我必须创建一个计数器来更新字符位置。这是必要的,因为 Matcher
与 content
变量相关联。因此,当它替换 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;
}
无论如何,我不知道这是不是最好的方法。