0

我们在 Catalyst 应用程序中使用 Template Toolkit。我们将 TT 配置为使用 UTF-8,之前没有任何问题。

现在我调用字符串 var 的 substr() 方法。不幸的是,它确实在n个字节而不是n个字符之后拆分字符串。如果第n(n+1)字节构建一个 unicode char,则它会被拆分,并且只有第一个字节是 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,
);
4

3 回答 3

3

我使用 Perl 1.12.2 对 MSWin32 模板模块进行了快速测试。它可以正确处理所有这些 substr 操作。

这是我的测试代码:

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 utf8nor DEFAULT_ENCODING。这里的关键点:

  1. 确保您的模板.tt文件使用BOM --Byte Order Mark编码为 UTF8 。这是必须做的任务!因为 Template-Toolkit 是根据 BOM 检测 Unicode 文件编码。

    • 您可以使用 Windows 记事本保存带有 BOM 的文件,只需执行File--> Save--> Encoding: "UTF-8"。
    • 您也可以使用 VIM 通过输入set fenc=utf8和来制作它set bomb,然后保存文件,文件将以 BOM 开头。
  2. NCODING参数设置Template->new({NCODING => 'utf-8'});为“utf-8”将强制Template将模板文件加载为“utf-8”。

  3. 建议use utf8在您的脚本中包含,它将确保您所有的内联字符串都正确编码为 utf8。

因为Catalyst::View::TT依赖于模板,我相信它应该也能正常工作!祝你好运~~~

于 2011-04-21T07:21:28.543 回答
0

答案很简单(在 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);

那会有帮助吗?

于 2011-04-21T06:37:12.097 回答
0

关于 UTF-8 的 Wikipedia 文章提供了一个表格,显示了非 ASCII 字符的编码方式。该表说明了 UTF-8 的以下简单规则:

  • 如果字节的最高位为 0,则该字节表示 ASCII 字符。

  • 如果一个字节的最高两位是11,那么这是一个多字节字符的开始,从最高位开始的连续1位的个数表示多字节字符中的字节总数。因此,位表示为 110xxxx 的字节是 2 字节字符的开头,1110xxxx 是 3 字节字符的开头,而 11110xxx 是 4 字节字符的开头。(您可以忽略假设的 5 字节和 6 字节字符,因为 Unicode 仅限于 21 位字符集而不是 32 位字符集。)

  • 如果一个字节的两个最高位是 10,那么这个字节是一个多字节字符的一部分(但不是那个字符的第一个字节)。

这些信息应该足以让您编写自己的实用程序函数,这些函数类似于但以字符而不是字节的形式工作string.lengthstring.substring()

更新:这个问题没有指定所使用的编程语言,我不知道“模板工具包”暗示使用 Perl。意识到这一点后,我进行了谷歌搜索,发现您的问题很可能是由于需要在use utf8源代码中添加指令。您可以在此处找到有关此的讨论。

于 2011-04-14T10:21:02.140 回答