从字符串中删除非 ASCII 字符?不涉及特殊字符。不需要替换它们

从字符串中删除非 ASCII 字符?不涉及特殊字符。不需要替换它们

浏览后,我发现这种问题已经针对其他编程语言(R,Python等)得到了解答,但没有针对TeX(特别是lualatex)回答。关于这个主题的唯一相关问题涉及特殊字符,或字符串替换,或非utf8编码。因此,MWE:

\documentclass{article} % Compile with lualatex.
\usepackage{fontspec}
\def\myname{Joseph “Jöey3” Xačengle}
\def\removenonascii#1{*this is what I ask*}
\begin{document}
\myname\par % expected: Joseph “Jöey3” Xačengle
\removenonascii{\myname}\par % expected: Joseph Jey3 Xaengle
\end{document}

所有非 ASCII 字符均已删除。请注意,花括号是非 ASCII 的(甚至不是 Latin-1)。小写 oumlaut 是 Latin-1,但不是 ASCII。ccaron 是非 ASCII 的,非 Latin-1。但我不在乎是否有任何东西是 Latin-1,只要是 ASCII 就行。编码始终为 utf8。

参数是\removenonascii已经扩展为文本的宏。由于它是一个宏,我认为我不能逐字使用。

我会将其用作\removenonascii{\myname}另一个宏的参数,该宏无需在此处定义。如果所有输入字符都是 ASCII,我可以对另一个宏进行编程(我希望如此)。

还有一件事:输入字符串(在本例中为\myname)将包含很少的非 ASCII 字符。换句话说,我正在使用(主要是西欧)语言。但是包的\StrSubstitute或函数似乎不适合这项任务,因为可能会出现大量可能的非 ASCII 字符。\StrDelxstring

答案1

下面的代码\text_purify:n首先删除非字符部分(数学模式不受影响),同时完全展开可扩展宏。然后,它逐个字素地使用\text_map_function:nN并将每个字素转发给一个函数,该函数尝试猜测以下内容是否为有效的 ASCII。

作为决策规则,使用标记数(在 pdfLaTeX 中,任何两个标记都是非 ASCII 的),然后如果它是单个标记,则检查字符代码是否小于 128(否则它是非 ASCII)。这应该适用于所有主流引擎。

\documentclass[]{article}

\ExplSyntaxOn
\cs_new:Npn \rallg_remove_non_ascii:n #1
  { \text_map_function:nN { \text_purify:n {#1} } \__rallg_remove_non_ascii:n }
\prg_new_conditional:Npnn \__rallg_if_ascii_range:n #1 { T }
  {
    \tl_if_single_token:nT {#1}
      {
        \int_compare:nNnTF { `#1 } < { 127 }
          \prg_return_true:
      }
    \prg_return_false:
  }
\cs_new:Npn \__rallg_remove_non_ascii:n #1
  { \__rallg_if_ascii_range:nT {#1} {#1} }
\cs_new_eq:NN \removenonascii \rallg_remove_non_ascii:n
\ExplSyntaxOff

\def\myname{Joseph “Jöey3” Xačengle}

\begin{document}
\myname\par % expected: Joseph “Jöey3” Xačengle
\removenonascii{\myname}\par % expected: Joseph Jey3 Xaengle
\end{document}

答案2

这里我使用了一个令牌循环。宏和分组也被从结果中删除,但如果想要保留它们,那将是一个简单的更改。

\documentclass{article}
\usepackage{tokcycle}
\Characterdirective{\ifnum`#1<128\addcytoks{#1}\fi}
\Groupdirective{\processtoks{#1}}
\Macrodirective{}
\Spacedirective{\addcytoks{#1}}
\stripgroupingtrue
\newcommand\onlyascii[1]{\expandafter\tokencyclexpress#1\endtokencyclexpress}
\begin{document}
\def\myname{Joseph “Jöey3” Xačengle \textit{hi Möm}}
\myname

\onlyascii{\myname}

Note macros, braces gone: \detokenize\expandafter{\the\cytoks}
\end{document}

在此处输入图片描述

如上所述,稍作调整将允许保留宏和分组:

\documentclass{article}
\usepackage[T1]{fontenc}% use with pdflatex only
\usepackage{tokcycle}
\Characterdirective{\ifnum`#1<128\addcytoks{#1}\fi}
\Groupdirective{\processtoks{#1}}
\Macrodirective{\ifactivetok\else\addcytoks{#1}\fi}
\Spacedirective{\addcytoks{#1}}
\newcommand\onlyascii[1]{\expandafter\tokencyclexpress#1\endtokencyclexpress}
\begin{document}
\def\myname{Joseph “Jöey3” Xačengle \textit{hi Möm}}
\myname

\onlyascii{\myname}

Note macros, braces retained: \detokenize\expandafter{\the\cytoks}
\end{document}

在此处输入图片描述

在 xelatex 或 lualatex 中编译时,测试\ifnum...<128...\fi会捕获非 ASCII 字符,而\ifactivetok\else...\fi在 pdflatex 中编译时,测试会捕获它们。

相关内容