我目前正在一个项目中使用expl3
代码。这是一个缓慢的学习过程。
现在我需要处理 UTF-8 输入流,但是,我已经怀疑处理 2 字节编码存在问题。
实际上,输入是否为 UTF-8 与我的情况无关。例如,我想要处理并até
得到以下结果:a
、t
和。换句话说,一次处理一个字节。在 LaTex 中,我想要得到类似的东西 ,并有4 个标记 tl。0xC3
0xA9
\processtl{até}
at{0xC3}{0xA9}
\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\ExplSyntaxOn
\newcommand{\processtl}[1]{
\tl_set:Nn \l_tokens_tl { #1 }
\tl_map_inline:Nn \l_tokens_tl { (##1) } %% Here: check one byte!
}
\ExplSyntaxOff
\begin{document}
token list: \processtl{abc{$\beta$}}\par
% token list with á and ç: \processtl{ábç{$\beta$}}\par % FAILS
\end{document}
有没有办法识别它0xC3
并将其与后面的字节分开处理?
就像是:
\IfTestByte{#1=0xC3){ % check if current byte is the first UTF-8
\showinhexadecimal(0xC3} % output it in hex
\getnexttoken % get the second byte
\showinhexadecimal{\thenexttoken} % output it in hex
}
我无法转换tl
,str
因为某些标记可以是宏,并且可以对str
它们进行反标记。
我查看了这些char
功能,但找不到任何有用的功能。我是不是错过了什么有用的东西?
答案1
使用pdflatex
函数\tl_map_inline:nn
只会将其á
视为两个字节。我们可以检查字符代码是否为高字节并采取相应措施。如果传递给它的对象不止一个标记,例如 for {$\beta$}
,我们可以按原样打印它。
\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\ExplSyntaxOn
\NewDocumentCommand{\processtl}{m}
{
\jander_process_tl:n { #1 }
}
\cs_new_protected:Nn \jander_process_tl:n
{
\tl_map_inline:nn { #1 }
{
( % open parenthesis
\tl_if_single:nTF { ##1 }
{
\__jander_process_highbyte:en { `\token_to_str:N ##1 } { ##1 }
}
{ ##1 }
) % close parenthesis
}
}
\cs_new:Nn \__jander_process_highbyte:nn
{
\int_compare:nTF { #1>127 } { 0x\int_to_Hex:n { #1 } } { #2 }
}
\cs_generate_variant:Nn \__jander_process_highbyte:nn { e }
\ExplSyntaxOff
\begin{document}
token list: \processtl{abc{$\beta$}}
token list with á and ç: \processtl{ábç{$\beta$}}
\end{document}
会发生什么?当á
找到时,它后面实际上0xC3
跟着0xA1
。就 而言,无论是哪种情况,它都是单个标记的序列pdftex
。所以我们可以计算它的字符代码(但我们需要使其成为“其他字符”,因为它可能是活动的),并将其传递给另一个函数,检查它是否是高字节。
考虑到单个标记可能是一个控制序列,进行了修改。
\documentclass[a4paper]{article}
\ExplSyntaxOn
\NewDocumentCommand{\processtl}{m}
{
\sys_if_engine_pdftex:TF
{
\jander_process_tl_onebyte:n { #1 }
}
{
\jander_process_tl_unicode:n { #1 }
}
}
\cs_new_protected:Nn \jander_process_tl_onebyte:n
{
\tl_map_inline:nn { #1 }
{
( % open parenthesis
\bool_lazy_or:nnTF { ! \tl_if_single_p:n { ##1 } } { \token_if_cs_p:N ##1 }
{
##1
}
{
\__jander_process_highbyte:en { `\token_to_str:N ##1 } { ##1 }
}
) % close parenthesis
}
}
\cs_new:Nn \__jander_process_highbyte:nn
{
\int_compare:nTF { #1>127 } { 0x\int_to_Hex:n { #1 } } { #2 }
}
\cs_generate_variant:Nn \__jander_process_highbyte:nn { e }
\ExplSyntaxOff
\begin{document}
token list: \processtl{abc{$\beta$}}
token list with á and ç: \processtl{ábç{$\beta$}\LaTeX}
\end{document}
节省编码的技巧是使用\bool_lazy_or:nnTF
;第一个条件为“没有单个标记”,第二个条件为“控制序列”。由于我们使用惰性求值,当第一个条件为真时(因此我们没有单个标记),第二个条件不会被求值。
答案2
我认为你想要这样的东西(只要多花点功夫就可以用十六进制打印)
\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\ExplSyntaxOn
\makeatletter
\newcommand{\processtl}[1]{{
\def\UTFviii@two@octets##1{\number\expandafter`\string##1}
\def\UTFviii@invalid@err##1{\number\expandafter`\string##1}
\tl_map_inline:nn {#1} { (##1) } %% Here: check one byte!
}}
\makeatother
\ExplSyntaxOff
\begin{document}
token list: \processtl{abc{$\beta$}}
token list with á and ç: \processtl{ábç{$\beta$}}\par % FAILS
\end{document}