我有一个格式化单个字符的命令,我们称之为\d{}
。 (在我的例子中, \d{} 在中文字符下添加一个点,因为这是强调中文文本的习惯)。
我想定义一个新命令\ds{}
,使其适用\d{}
于字符串的每个字母。
例如\ds{abc}
相当于\d{a}\d{b}\d{c}
。
谢谢!
答案1
您可以使用\@tfor
。我还根据您的意愿提供了下面的点的更好的重新定义:
\documentclass{article}
\usepackage{graphicx}
\let\d\relax
\DeclareRobustCommand{\d}[1]{%
\oalign{#1\cr\hidewidth\scalebox{0.5}{\textbullet}\hidewidth\cr}%
}
\makeatletter
\newcommand{\ds}[1]{%
\@tfor\next:=#1\do{\d{\next}}%
}
\makeatother
\begin{document}
x\d{d}\d{s}\d{a}x
x\ds{dsa}x
\end{document}
做什么\@tfor
?它的语法是
\@tfor<scratch macro>:=<tokens>\do{<code>}
临时宏传统上是\next
,但它可以是任何东西。<tokens>
部分是任何(括号平衡)标记列表。在循环中,LaTeX 本质上是\def<scratch macro>{<next token>}
,因此
\@tfor\next:=dsa\do{\d{\next}}
将执行
\def\next{d}\d{\next}\def\next{s}\d{\next}\def\next{a}\d{\next}
然而,\@tfor\next:=d {sa}\do{\d{\next}}
我们只会得到
\def\next{d}\d{\next}\def\next{sa}\d{\next}
显式空格标记将被忽略,并且括号内的标记组将被视为一个。
类似的例子expl3
是\tl_map_inline:nn
:
\documentclass{article}
\usepackage{xparse}
\usepackage{graphicx}
\let\d\relax
\DeclareRobustCommand{\d}[1]{%
\oalign{#1\cr\hidewidth\scalebox{0.5}{\textbullet}\hidewidth\cr}%
}
\ExplSyntaxOn
\NewDocumentCommand{\ds}{m}
{
\tl_map_inline:nn { #1 } { \d { ##1 } }
}
\ExplSyntaxOff
\begin{document}
x\d{d}\d{s}\d{a}x
x\ds{dsa}x
x\ds{d sa{bc}}x
\end{document}
#1
没有使用临时宏:循环中的当前项由(像往常一样,成为##1
定义主体中的一部分)表示。
在这种特殊情况下,仅应用一个命令并使用当前项目作为参数,可以使用\tl_map_function:nN
:
\NewDocumentCommand{\ds}{m}
{
\tl_map_function:n { #1 } \d
}
效果相同,但更短。它也可以出现在完整扩展上下文中(由于 ,不适用于此特定情况\d
)。
答案2
此解决方案允许自动换行并处理单词之间的空格。此外,该[w]
选项允许对每个单词而不是每个字符执行任务。'
在 MWE 中,我通过各种定义的任务进行了演示:
重打每个字符(2 种不同的设置)
在每个字符下放一个点
每个单词下加一个分号
应用额外的字符间距
应用额外的词间空间。
\charop{}
任务在for 字符和\wordop{}
for 单词中定义,而\chariterate[]{}
宏执行迭代。以下是 MWE:
% WHILE THIS EXAMPLE IS SET UP FOR BOLDING A CALLIGRAPHIC FONT
% ITS GENERAL USE IS TO DO SOMETHING ON EACH char OF ITS ARGUMENT, ALLOWING LINE WRAP
% THE [W] OPTION TO \chariterate DOES SOMETHING TO EACH WORD.
\documentclass[10pt,a4paper,BCOR10mm,DIV11,toc=listof,parskip=full, openany]{scrbook}
\usepackage{stackengine}
\newcommand\chariterate[2][c]{\if w#1\worditeratehelper#2 \relax\relax\else
\chariteratehelpA#2 \relax\relax\fi}
\def\chariteratehelpA#1 #2\relax{%
\chariteratehelpB#1\relax\relax%
\ifx\relax#2\else\ \chariteratehelpA#2\relax\fi
}
\def\chariteratehelpB#1#2\relax{%
\charop{#1}%
\ifx\relax#2\else
\chariteratehelpB#2\relax%
\fi
}
\def\worditeratehelper#1 #2\relax{%
\wordop{#1}%
\ifx\relax#2\else\ \worditeratehelper#2\relax\fi
}
\def\charop#1{#1}
\def\wordop#1{#1}
% THIS EXAMPLE ARTIFICIALLY BOLDS EACH char WITH A SHIFTED OVERSTRIKE
\def\charopA{%
%\def\useanchorwidth{T}%
\def\stacktype{L}%
\def\stackalignment{l}%
\def\calup{.2pt}%
\def\calover{.15pt}%
\renewcommand\charop[1]{\stackon[\calup]{##1}{\kern\calover##1}}%
}
% HERE'S AN EXAMPLE PLACING DOT UNDER EACH char
\def\charopB{%
\def\useanchorwidth{T}%
\def\stacktype{L}%
\def\stackalignment{c}%
\renewcommand\charop[1]{\stackunder[3pt]{##1}{.}}%
}
% EXTRA INTER-CHARACTER SPACE
\def\charopC{\renewcommand\charop[1]{##1\,}}
% HERE'S AN EXAMPLE PLACING DOT UNDER EACH WORD
\def\wordopA{%
\renewcommand\wordop[1]{\def\stackalignment{c}\stackunder[3pt]{##1}{;}}
}
% EXTRA INTER-WORD SPACE
\def\wordopB{\renewcommand\wordop[1]{##1\ \ }}
%
\newenvironment{calligraphic}%
{\fontencoding{T1}\fontfamily{pzc}\fontseries{m}\fontshape{it}\fontsize{12pt}{12pt}\selectfont}{}%
\renewcommand*{\sectfont}{\normalcolor\usefont{T1}{pzc}{m}{it}}
\begin{document}
\charopA
\begin{calligraphic}
Test \textbf{this is not bold}\par
Test \chariterate{this is bold with .2pt up shift and .15pt right shift}\par
\def\calup{.0pt}
\def\calover{.2pt}
Test \chariterate{this is bold with .0pt up shift and .2pt right shift}\par
\chariterate{cvxc This is a test. This is a test. This is a test. This is a test.
This is a test. This is a test. This is a test. This is a test. This is a
test. This is a test. This is a test. This fdsfsd is a test. This is a test.
This is a test. This is a test. This is adfsdf test. This is a test.}\par
\end{calligraphic}\par
\charopB
\wordopA
\chariterate{This is doing something to each character.}\par
\chariterate[w]{This is doing something to each word.}\par
\chariterate{Ich bin m{\"u}de}.
\chariterate[w]{Ich bin m{\"u}de}.\par
\charopC
\wordopB
\chariterate{This is doing something to each character.}\par
\chariterate[w]{This is doing something to each word.}\par
\end{document}
在最简单的情况下,仅对字符执行下点操作,代码可以大大减少:
\documentclass{article}
\usepackage{stackengine}
\newcommand\chariterate[2][c]{\if w#1\worditeratehelper#2 \relax\relax\else
\chariteratehelpA#2 \relax\relax\fi}
\def\chariteratehelpA#1 #2\relax{%
\chariteratehelpB#1\relax\relax%
\ifx\relax#2\else\ \chariteratehelpA#2\relax\fi
}
\def\chariteratehelpB#1#2\relax{%
\charop{#1}%
\ifx\relax#2\else
\chariteratehelpB#2\relax%
\fi
}
\def\worditeratehelper#1 #2\relax{%
\wordop{#1}%
\ifx\relax#2\else\ \worditeratehelper#2\relax\fi
}
\def\useanchorwidth{T}%
\def\stacktype{L}%
\def\stackalignment{c}%
\newcommand\charop[1]{\stackunder[3pt]{#1}{.}}%
\def\wordop#1{#1}
\begin{document}
\chariterate{This is doing something to each character.
This is doing something to each character.
This is doing something to each character.}\par
\end{document}
答案3
这个问题非常适合我的新tokcycle
包,所以我只需要添加另一个答案。这里的好处是,即使文本样式发生变化并且调用宏,它也可以应用下划线。\underdot
仅适用于可打印的 cat-11 标记。
\documentclass{article}
\usepackage{tokcycle}
\newcommand\underdot[1]{\ooalign{#1\cr\hfil{\raisebox{-2.5pt}{.}}\hfil}}
\tokcycleenvironment\ds
{\tctestifcatnx A##1{\addcytoks{\underdot{##1}}}{\addcytoks{##1}}}% CHARACTER DIRECTIVE
{\processtoks{##1}}% GROUP-CONTENT DIRECTIVE
{\addcytoks{##1}}% MACRO DIRECTIVE
{\addcytoks{##1}}% SPACE DIRECTIVE
\begin{document}
\ds abc\endds
\ds This can work \textbf{across \bgroup\itshape changes in text
style\egroup, and can |escape text, for example $y=2x+1$| and pick
up where it left off}. However, only catcode-11 tokens are underdotted.
It can continue across paragraphs.
This is from the new \textsf{tokcycle} package released on 2019/8/21.
\endds
\end{document}