例如,如果描述是英文的,我可以得到80個字符,但是對於中文字符,我只能得到大約10個字符,並且有一個垃圾char總是在最後。如何獲得一段特殊字符的子字符串,例如中文
我怎樣才能得到80個字符的任何語言?
例如,如果描述是英文的,我可以得到80個字符,但是對於中文字符,我只能得到大約10個字符,並且有一個垃圾char總是在最後。如何獲得一段特殊字符的子字符串,例如中文
我怎樣才能得到80個字符的任何語言?
FreeMarker依靠String#substring
來進行實際的(基於UTF-16-chars的?)子串計算,這對中文字符不起作用。相反,應該使用Unicode代碼點。基於this post和FreeMarker的自己的子內建我砍死在一起,這對代碼點運行的FreeMarker的TemplateMethodModelEx
實現:
public class CodePointSubstring implements TemplateMethodModelEx {
@Override
public Object exec(List args) throws TemplateModelException {
int argCount = args.size(), left = 0, right = 0;
String s = "";
if (argCount != 3) {
throw new TemplateModelException(
"Error: Expecting 1 string and 2 numerical arguments here");
}
try {
TemplateScalarModel tsm = (TemplateScalarModel) args.get(0);
s = tsm.getAsString();
} catch (ClassCastException cce) {
String mess = "Error: Expecting numerical argument here";
throw new TemplateModelException(mess);
}
try {
TemplateNumberModel tnm = (TemplateNumberModel) args.get(1);
left = tnm.getAsNumber().intValue();
tnm = (TemplateNumberModel) args.get(2);
right = tnm.getAsNumber().intValue();
} catch (ClassCastException cce) {
String mess = "Error: Expecting numerical argument here";
throw new TemplateModelException(mess);
}
return new SimpleScalar(getSubstring(s, left, right));
}
private String getSubstring(String s, int start, int end) {
int[] codePoints = new int[end - start];
int length = s.length();
int i = 0;
for (int offset = 0; offset < length && i < codePoints.length;) {
int codepoint = s.codePointAt(offset);
if (offset >= start) {
codePoints[i] = codepoint;
i++;
}
offset += Character.charCount(codepoint);
}
return new String(codePoints, 0, i);
}
}
你可以把它的一個實例爲你的數據模型根,例如
SimpleHash root = new SimpleHash();
root.put("substring", new CodePointSubstring());
template.process(root, ...);
並使用FTL自定義字符串方法:
${substring(description, 0, 80)}
我非中國文字,這仍然工作,但到目前爲止,我還沒有與中國文字試過了測試。也許你想試試看。
你上面說過,Java的字符串方法不適合中文字符。實際上受影響的字符只是非BMP字符(它們也包含一些不常見的數學符號等),但這些字符在中文中並不罕見嗎? (中國容易擁有最大的FreeMarker用戶羣,讓美國落後,所以我很驚訝我從未聽說過這個問題。) – ddekany
只有當您使用非BMP字符時纔會發生這種情況,但AFAIK所有*常用*中文字符都在BMP內。這個問題有多頻繁?我的意思是,Java不支持這些字符,這是可疑的。 – ddekany