我偶尔会使用 Latex(这意味着我从来没有用它写过大篇幅的专业文章,但写过一些个人使用的文章),并且想创建一些名片,基本而简单,不做作但也不会太丑。
在这里,我想格式化我的 pgp 密钥指纹。通常 pgp 密钥每四位数字有一个空格,以使其更易读。
因此它转换如下:
47D6459B2DCEE5C1439C53330403A28B2D8DE8FB
变成这样:
47D6 459B 2DCE E5C1 439C 5333 0403 A28B 2D8D E8FB
那么如何在每组之间插入空格?
其次,如果我可以在中间创建一个新行,也就是在第 5 个空格处,那就太好了。我该怎么做?
47D6 459B 2DCE E5C1 439C
5333 0403 A28B 2D8D E8FB
我将用这个创建一个宏。谢谢帮助!
答案1
一个不检查字符串长度的简单解决方案:
\documentclass{article}
\makeatletter
\newcommand{\printpgp}[1]{\print@pgp#1\@nil}
\def\print@pgp#1#2#3#4#5\@nil{%
#1#2#3#4%
\ifx\\#5\\%
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{~\print@pgp#5\@nil}%
}
\makeatother
\begin{document}
$|$\printpgp{47D6459B2DCEE5C1439C53330403A28B2D8DE8FB}$|$
\end{document}
我在侧面添加了两个条,只是为了显示没有添加多余的空间。
如果要以等宽字体打印指纹,只需将第一个定义更改为
\newcommand{\printpgp}[1]{\texttt{\print@pgp#1\@nil}}
更多功能。如果长度错误,则打印“INVALID PGP”。字符串中的空格将被忽略。您可以指定一个键值接口:break
默认情况下为 true,但break=false
键会打印在一行上。font
您可以指定字体选择(默认\ttfamily
)。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\printpgp}{O{}m}
{
\par\noindent
\group_begin:
\keys_set:nn { xxiidecembre/printpgp } { #1 }
\xxiidecembre_printpgp:n { #2 }
\par
\group_end:
}
\keys_define:nn { xxiidecembre/printpgp }
{
font .tl_set:N = \l_xxiidecembre_pgpfont_tl,
font .initial:n = \ttfamily,
break .bool_set:N = \l_xxiidecembre_pgpbreak_bool,
break .initial:n = true,
}
\tl_new:N \l__xiidecembre_pgp_tl
\int_new:N \l__xxiidecembre_step_int
\int_new:N \l__xxiidecembre_group_int
\cs_new_protected:Npn \xxiidecembre_printpgp:n #1
{
\tl_use:N \l_xxiidecembre_pgpfont_tl
\tl_set:Nn \l__xiidecembre_pgp_tl { #1 }
\tl_replace_all:Nnn \l__xiidecembre_pgp_tl { ~ } { }
\int_compare:nTF { \tl_count:N \l__xiidecembre_pgp_tl = 40 }
{
\__xxiidecembre_printpgp:V \l__xiidecembre_pgp_tl
}
{
INVALID~PGP
}
}
\cs_new_protected:Npn \__xxiidecembre_printpgp:n #1
{
\tl_map_inline:nn { #1 }
{
##1
\int_incr:N \l__xxiidecembre_step_int
\int_compare:nT { \l__xxiidecembre_step_int = 4 }
{
\int_incr:N \l__xxiidecembre_group_int
\int_compare:nTF { \l__xxiidecembre_group_int = 5 }
{
\bool_if:NTF \l_xxiidecembre_pgpbreak_bool { \\ } { ~ }
}
{
\c_space_tl
}
\int_zero:N \l__xxiidecembre_step_int
}
}
}
\cs_generate_variant:Nn \__xxiidecembre_printpgp:n { V }
\ExplSyntaxOff
\begin{document}
\printpgp{47D6459B2DCEE5C1439C53330403A28B2D8DE8FB}
\medskip
\printpgp[break=false]{47D6459B2DCEE5C1439C53330403A28B2D8DE8FB}
\medskip
\printpgp[font=\ttfamily\LARGE]{47D6 459B 2DCE E5C1 439C 5333 0403 A28B 2D8D E8FB}
\medskip
\printpgp{0000 1111 2222}
\end{document}
首先删除空格,然后逐个字符地映射输入,每一步都增加一个计数器;如果计数器为 4,则组计数器将步进;发出一个空格,但\\
如果组计数器为 5 且break=true
有效,则使用空格。
答案2
这里的两个答案都使用了不太理想的参数操作方法,因为#5
循环中的每个步骤都会重写参数(其余数字)。更好的解决方案是:
\newcount\tmpnum
\def\pgp#1{\tmpnum=0 \pgpA #1 {}...}
\def\pgpA#1#2#3#4{\ifx^#1^\unskip\else
\ifnum\tmpnum=5\par\fi
\advance\tmpnum by1
#1#2#3#4
\expandafter\pgpA\fi}
\pgp{47D6459B2DCEE5C1439C53330403A28B2D8DE8FB}
答案3
\documentclass{scrartcl}
\newcount\pgpcount
\long\def\firstofone#1{#1}
\long\def\gobbleone#1{}
\def\dopgp#1#2#3#4#5\relax
{#1#2#3#4\if\relax\detokenize{#5}\relax
\expandafter\gobbleone
\else
\expandafter\firstofone
\fi
{\advance\pgpcount by 1
\ifnum\pgpcount=5
\par\pgpcount=0
\else\ \fi
\dopgp#5\relax\unskip}}
\def\pgp#1{\dopgp#1\relax}
\begin{document}
\pgp{47D6459B2DCEE5C1439C53330403A28B2D8DE8FB}
\end{document}
egreg 打败了我,但我想这是我第一次玩“TeX 宏”,所以我就把它留在这里了。
答案4
我很惊讶还没有基于 luatex 的解决方案。这是 ConTeXt 中的一个解决方案,适用于平衡和非平衡输入。我定义了一个单独的突出显示来更改输出的样式(等宽字体等)。
\startluacode
local C, Ct = lpeg.C, lpeg.Ct
local lpegmatch = lpeg.match
local hexdigit = lpeg.patterns.hexdigit
local concat = table.concat
userdata = userdata or {}
userdata.splitPGP = function(str)
local block = C(hexdigit * hexdigit * hexdigit * hexdigit)
local nonblock = C(hexdigit^0)
local pattern = Ct(block^0 * nonblock)
local tbl = lpegmatch(pattern, str)
context.PGPstyle(concat(tbl, " "))
end
\stopluacode
\definehighlight[PGPstyle][style=mono]
\define[1]\splitPGP{\ctxlua{userdata.splitPGP([==[#1]==])}}
\starttext
\startlines
\splitPGP{47D6459B2DCEE5C1439C53330403A28B2D8DE8FB}
\splitPGP{47D6459B2DCEE5C1439C53330403A28B2D8DE8}
\stoplines
\stoptext