2011-10-07 68 views
3

例如,如果描述是英文的,我可以得到80个字符,但是对于中文字符,我只能得到大约10个字符,并且有一个垃圾char总是在最后。如何获得一段特殊字符的子字符串,例如中文

我怎样才能得到80个字符的任何语言?

+0

只有当您使用非BMP字符时才会发生这种情况,但AFAIK所有*常用*中文字符都在BMP内。这个问题有多频繁?我的意思是,Java不支持这些字符,这是可疑的。 – ddekany

回答

3

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)} 

我非中国文字,这仍然工作,但到目前为止,我还没有与中国文字试过了测试。也许你想试试看。

+0

你上面说过,Java的字符串方法不适合中文字符。实际上受影响的字符只是非BMP字符(它们也包含一些不常见的数学符号等),但这些字符在中文中并不罕见吗? (中国容易拥有最大的FreeMarker用户群,让美国落后,所以我很惊讶我从未听说过这个问题。) – ddekany

相关问题