Инструментарий шаблонов somevar.substr () и UTF-8 - PullRequest
0 голосов
/ 12 апреля 2011

Мы используем Template Toolkit в приложении Catalyst.Мы настроили TT для использования UTF-8 и раньше у него не было проблем.

Теперь я вызываю метод substr () для строки var.К сожалению, он разбивает строку после n байтов вместо n символов.Если n 'th и (n + 1) ' байт строят символ в юникоде, он разделяется, и только 1-й байт является частью результата substr ().

Как исправить или обойти это поведение?

[% string = "fööbär";

string.length; # prints 9

string.substr(0, 5); # prints "föö" (1 ascii + 2x 2 byte unicode)

string.substr(0, 4): # prints "fö?" (1 ascii, 1x 2 byte unicode, 1 unknown char)
%]

До сих пор у нас не было проблем с символами Unicode, ни из базы данных, ни из текста в шаблонах.

Редактировать: Вот как я настраиваю модуль Catalyst::View::TT в своем приложении Catalyst:

__PACKAGE__->config(
#   DEBUG => DEBUG_ALL,
    DEFAULT_ENCODING => 'utf-8',
    INCLUDE_PATH => My::App->path_to( 'root', 'templates' ),
    TEMPLATE_EXTENSION => '.tt',
    WRAPPER => "wrapper/default.tt",
    render_die => 1,
);

Ответы [ 3 ]

3 голосов
/ 21 апреля 2011

Я провел быстрое тестирование с Perl 1.12.2 для модуля шаблона MSWin32.Он мог бы правильно обрабатывать все эти операции.

Это мой тестовый код:

use Template;

# some useful options (see below for full list)
my $config = {
#    DEFAULT_ENCODING => 'utf-8',
    INCLUDE_PATH => 'd:/devel/perl',  # or list ref
    INTERPOLATE  => 1,               # expand "$var" in plain text
    EVAL_PERL    => 1,               # evaluate Perl code blocks
};

# create Template object
my $template = Template->new($config);

# define template variables for replacement
my $vars = {
    var1  => "abcdef"
};

# specify input filename, or file handle, text reference, etc.
my $input = 'ttmyfile.txt';

# process input template, substituting variables
print $template->process($input, $vars);

ttmyfile.txt

Var = [% var1 %]

[% string = "fööbär" -%]
[% string.length %]   # prints 6
[% string.substr(0, 5) %]  # prints "fööbä"
[% string.substr(0, 4) %]  # prints "fööb" 

Вывод:

Var = abcdef

6     # prints 6
fööbä  # prints "fööbä"
fööb  # prints "fööb" 
1

Все работает нормально, даже безuse utf8 ни DEFAULT_ENCODING.Ключевые вещи здесь:

  1. Убедитесь, что ваши шаблоны .tt файлы закодированы как UTF8 с BOM - Byte Order Mark.Это обязательная задача!Потому что Template-Toolkit определяет кодировку файлов Unicode в соответствии с спецификацией.

    • Вы можете использовать Блокнот Windows для сохранения файла с спецификацией, просто сделайте File -> Save -> Кодировка: "UTF-8".
    • Вы можете также использовать VIM, введя set fenc=utf8 и set bomb, затем сохраните файл, файл начнется с спецификации.
  2. Установите параметр NCODING Template->new({NCODING => 'utf-8'}); в качестве 'utf-8', что заставит Template загрузить файл шаблона как 'utf-8'.

  3. Предложите, чтобы в вашем скрипте было use utf8, это обеспечит правильное кодирование всех ваших встроенных строк как utf8.

Поскольку Catalyst::View::TT полагается на шаблонЯ считаю, что это должно работать!Удачи ~~~

0 голосов
/ 21 апреля 2011

Ответ довольно прост (на Perl), к счастью:

use Encode qw{encode decode};

Способ, которым это работает, заключается в том, что вы декодируете строки Unicode в строки Perl, после чего вы можете использовать substr () и length () так, как вы ожидаете, а затем снова кодируете их для вывода.

С этим заголовком:

# $unicodeString = 'fööbär';
my $perlString = decode('UTF-8', $unicodeString);
printf "%d\n", length($perlString);  # should be 6
printf "%s\n", substr($perlString, 0, 3);  # should be 'föö'
# whatever other processing you want here with $perlString . . .
# Then, you want to reencode that back to a proper UTF-8 string:
my $unicodeString = encode('UTF-8', $perlString);

Это поможет?

0 голосов
/ 14 апреля 2011

Статья в Википедии об UTF-8 содержит таблицу, в которой показано, как символы, не входящие в ASCII, кодируются . Эта таблица иллюстрирует следующие простые правила для UTF-8:

  • Если старший бит байта равен 0, то этот байт обозначает символ ASCII.

  • Если два старших бита байта равны 11, то это начало многобайтового символа, а количество последовательных 1 бит, начиная с бита самого высокого порядка, указывает общее количество байтов в многобайтовый символ. Таким образом, байт, битовое представление которого равно 110xxxxx, является началом 2-байтового символа, 1110xxxx является началом 3-байтового символа, а 11110xxx является началом 4-байтового символа. (Вы можете игнорировать гипотетические 5-байтовые и 6-байтовые символы, потому что Unicode ограничен 21-битным набором символов, а не 32-битным набором символов.)

  • Если два старших бита байта равны 10, то этот байт является частью многобайтового символа (но не первый байт этого символа).

Этой информации должно быть достаточно для написания собственных служебных функций, подобных string.length и string.substring(), но работающих в виде символов вместо байтов.

Обновление: В вопросе не указан используемый язык программирования, и я не знал, что "Template Toolkit" подразумевает использование Perl. Как только я понял это, я выполнил поиск в Google и обнаружил, что ваша проблема, вероятно, связана с необходимостью добавить директиву use utf8 в ваш исходный код. Вы можете найти обсуждение этого здесь .

...