Как получить подстроку определенной длины для специальных символов, таких как китайский - PullRequest
3 голосов
/ 07 октября 2011

Например, я могу получить 80 символов с помощью {description?substring(0, 80)}, если описание написано на английском языке, но для китайских символов я могу получить только около 10 символов, и в конце всегда есть символ мусора.

Как я могу получить 80 символов для любого языка?

1 Ответ

3 голосов
/ 09 октября 2011

FreeMarker использует String#substring для выполнения фактического вычисления подстроки (на основе UTF-16-chars?), Что не очень хорошо работает с китайскими иероглифами.Вместо этого следует использовать кодовые точки Unicode.Основываясь на этой записи и собственной встроенной подстроке 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);
    }
}

Вы можете поместить его экземпляр в свою модель данныхroot, например

SimpleHash root = new SimpleHash();
root.put("substring", new CodePointSubstring());
template.process(root, ...);

и использовать пользовательский метод подстроки в FTL:

${substring(description, 0, 80)}

Я протестировал его с некитайскими символами, которые все еще работали, но до сих пор у меня нетпопробовал с китайскими иероглифами.Может быть, вы хотите попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...