2011-10-07 94 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

相關問題