五一假期結(jié)束了悔叽。新的一周開始了莱衩,繼續(xù)奮斗!
吐槽一下前幾天被人忽視了骄蝇,心里小小的不爽了一下膳殷。算了,就不跟那些人一般見識了九火,阿Q精神還是要的赚窃。
開始今天的記錄
已經(jīng)上線運(yùn)行的項目,突然加介紹人英文資料的時候岔激,想要文字出現(xiàn)上角標(biāo)勒极,但是沒有效果。想一想虑鼎,簡單嗎辱匿?可以用富文本嗎!說干就干炫彩,何止是上標(biāo)匾七,下標(biāo)也一樣可以加上。
span.setSpan(new SuperscriptSpan(), 31, 33, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //上標(biāo)
span.setSpan(new SubscriptSpan(), 33, 35, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //下標(biāo)
text.append(span);
so easy!
但是=ぁW蛞洹!
但是I荚省R靥!
加入一段文字不知道在什么地方會需要上標(biāo)呢叔磷?比如1st拢驾。
參考:https://blog.csdn.net/zhangxiangliang2/article/details/73658011
首先是獲取到需要上標(biāo)的位置
當(dāng)然是用到用到一個正則表達(dá)式:(?<=\b\d{1,10})(st|nd|rd|th)(?=\b)
這個正則表達(dá)式分為三個部分:
(?<=\b\d{1,10})
(st|nd|rd|th)
(?=\b)
第一部分是后行斷言(lookbehind),用來匹配我們希望展示內(nèi)容之前的指定模式。后行斷言用?<=表示改基,后面跟著我們希望匹配的模式繁疤。
此處\b\d{1,10}要么匹配一個空格或者是一個字符串的開始(\b代表);然后后面跟1到10的數(shù)字(\d{1,10}代表)。
在java中不可能用通配符匹配后行斷言嵌洼,因為假如編譯器無法確定后行斷言的最大長度正則編輯會失敗案疲,這就是我為什么在這里指定了一個范圍,而不是使用\d+麻养。
第二部分是我們真正要展示的內(nèi)容。正如我們想要展示的序數(shù)后綴诺舔,我們使用(st|nd|rd|th)鳖昌。
第三部分是先行斷言(lookahead),用來匹配我們希望展示內(nèi)容之后的指定模式。后行斷言用?=表示低飒,后面跟著我們希望匹配的模式许昨。
此處\b要么匹配一個空格要么匹配一個字符串的結(jié)尾(\b代表)。
認(rèn)真的你可能會想到一個問題褥赊,為什么我們不只用第二個部分就可以了呢?
因為這樣我們會在“first”上匹配"st"成first,很明顯這不是我們想要的糕档。
正確使用先行斷言與后行斷言才能達(dá)到我們的目的,最后我們要匹配如下的模式:
<whitespace or start><one or more digits>st|nd|rd|th<whitespace or end>
其次是用富文本設(shè)置成上標(biāo)
SuperscriptSpan superscript = new SuperscriptSpan();
RelativeSizeSpan size = new RelativeSizeSpan(PROPORTION);
stringBuilder.setSpan(superscript, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.setSpan(size, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
其中使用SuperscriptSpan來升高文字基準(zhǔn)線拌喉,RelativeSizeSpan來改變TextView文字大小速那。
封裝好的工具類
public class OrdinalSuperscriptFormatter {
private static final String SUPERSCRIPT_REGEX = "(?<=\\b\\d{0,10})(st|nd|rd|th)(?=\\b)";
private static final Pattern PATTERN = Pattern.compile(SUPERSCRIPT_REGEX);
private static final float PROPORTION = 0.5f;
private final SpannableStringBuilder stringBuilder;
public OrdinalSuperscriptFormatter(@NonNull SpannableStringBuilder stringBuilder) {
this.stringBuilder = stringBuilder;
}
//執(zhí)行正則表達(dá)式的邏輯
public void format(TextView textView) {
CharSequence text = textView.getText();
Matcher matcher = PATTERN.matcher(text);
stringBuilder.clear();
stringBuilder.append(text);
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
createSuperscriptSpan(start, end);
}
textView.setText(stringBuilder);
}
private void createSuperscriptSpan(int start, int end) {
SuperscriptSpan superscript = new SuperscriptSpan();
RelativeSizeSpan size = new RelativeSizeSpan(PROPORTION);
stringBuilder.setSpan(superscript, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.setSpan(size, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
使用
TextView textView = (TextView) findViewById(R.id.text_view);
OrdinalSuperscriptFormatter formatter = new OrdinalSuperscriptFormatter(new SpannableStringBuilder());
formatter.format(textView);
效果如下
附上TextView高級用法使用TextView實現(xiàn)更多效果
以上使用還是會出現(xiàn)一些問題,比如我就想顯示1 th尿背,不想弄成1 th端仰,由于上邊的斷言種\b包含了空格,所以需要處理空格的問題田藐。
所以最后修改為 \S(?<=\b\d{0,10})(st|nd|rd|th)(?=\b)
不過一般情況下不會出現(xiàn)這種情況荔烧,用上邊的就ok了。