Perl 模板工具包';s somevar.substr()和UTF-8

Perl 模板工具包';s somevar.substr()和UTF-8,perl,encoding,utf-8,substr,template-toolkit,Perl,Encoding,Utf 8,Substr,Template Toolkit,我们在Catalyst应用程序中使用模板工具包。我们将TT配置为使用UTF-8,以前没有任何问题 现在我调用string变量的substr()方法。不幸的是,它在n个字节后而不是n个字符后分割字符串。如果第n个字节和(n+1)个字节生成unicode字符,则会将其拆分,并且只有第1个字节是substr()结果的一部分 如何纠正或解决该行为? [% string = "fööbär"; string.length; # prints 9 string.substr(0, 5); # print

我们在Catalyst应用程序中使用模板工具包。我们将TT配置为使用UTF-8,以前没有任何问题

现在我调用string变量的substr()方法。不幸的是,它在n个字节后而不是n个字符后分割字符串。如果第n个字节和(n+1)个字节生成unicode字符,则会将其拆分,并且只有第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应用程序中配置
Catalyst::View::TT
模块的方式:

__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,
);

Wikipedia关于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()
,但以字符而不是字节为单位


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

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

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

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

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

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


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

答案非常简单(用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);

这会有帮助吗?

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

这会有帮助吗?

我使用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
即使没有
使用utf8
默认编码
,所有这些都可以正常工作。这里的重点是:

  • 确保您的模板
    .tt
    文件编码为UTF8。这是一项必须完成的任务!因为模板工具包是根据BOM检测Unicode文件编码的

    • 您可以使用Windows记事本保存带有BOM表的文件,只需执行
      file
      -->
      save
      -->编码:“UTF-8”
    • 通过输入
      set fenc=utf8
      set bomb
      ,您也可以使用VIM制作,然后保存文件,文件将以BOM开头
  • 设置
    NCODING
    参数
    Template->new({NCODING=>'utf-8'})作为“utf-8”将强制
    模板
    以“utf-8”的形式加载模板文件

  • 建议在脚本中使用utf8,这样可以确保所有内联字符串都正确编码为utf8


  • 因为
    Catalyst::View::TT
    依赖于模板,所以我相信它也应该可以工作!祝你好运~~~

    我用Perl1.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
    
    即使没有
    使用utf8
    默认编码
    ,所有这些都可以正常工作。关键的事情