例如,如果描述是英文的,我可以得到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