我正在尝试使用 tikz 绘制穿孔卡片。该卡片是一个 8 x 80 矩阵。卡片通过编码方案(例如 ASCII)在卡片标题中“存储”一个句子(例如程序源代码中的一行)。每列用二进制代码表示一个句子字符:第 0 列表示第一个字符,第 1 列表示第二个字符,依此类推。显然,一个句子不能超过 80 个字符。一行中的孔表示相应的代码位为 1;“非孔”表示 0。例如,如果第 11 个位置的字符是“A”(二进制中的 65 或 01000001),则第 10 列的第 0 行和第 6 行中有一个孔。
使用 binhex 库 \nbinary 宏,我可以获得与十进制数相对应的 1 和 0 的字符串;使用 xstring 包中的 \StrChar 宏,我可以获得这些“位”,但从左到右,这会使孔出现在卡片的错误位置(例如,在“A”的情况下,孔出现在第 7 行和第 5 行)。
我的另一个问题是我无法逐个获取句子的位置(所有列的打印字符都是相同的)。
我的代码:
\documentclass[16pt,a4paper, openright,twoside, fleqn]{book}
\usepackage{tikz}
\usetikzlibrary{arrows, arrows.meta, backgrounds,calc, chains, calligraphy, decorations.pathreplacing, decorations.markings, external, fit,positioning, scopes, ,shapes.arrows, shapes.multipart, shapes.symbols, shapes.geometric, shapes.callouts, shadows, shadows.blur, tikzmark}
\usepackage{xstring}
\usepackage{ifthen}
\usepackage{stix}
\begin{document}
\input binhex
\def\word{\nbinary{8}{0}} % Fixed ASCII
\begin{tikzpicture}[scale=.4, transform shape]
\node[rectangle, draw, rounded corners=1ex, fit={(-1,1) (37, -11)}, line width = 0.4mm, ] (card) {};
\node[text centered, below right = 3mm and 1cm of card.north west] {{\huge \texttt{IF WS-NUM1 IS GREATER THAN OR EQUAL TO WS-NUM2 THEN}}};
\foreach \x [count = \yi] in {0, ..., 79} {
\node[text centered] at (\x*.45,-11) {\x};
}
\foreach \x [count = \xi] in {0, 1, 2, ..., 79}{
\foreach \k [count = \ki] in {1, ..., 8}{
\StrChar{\word}{\k}[\bit]
\ifthenelse{\equal{\bit}{1}}{
\node[text centered, minimum size=2mm, text width=2mm] at (\x*.45,\k *-1.2) {{\huge $\talloblong$}};
}
{
\node[text centered, minimum size=2mm, text width=2mm] at (\x*.45,\k *-1.2) {\number\numexpr 1-\k \relax};
}
}
}
\end{tikzpicture}
\end{document}
提前致谢!
答案1
答案2
这是一些函数,它可以转换列表中的二进制文件,并在前面添加足够多的零,以使列表具有固定长度。然后,您可以循环遍历此列表以绘制列条目。我只是使用随机二进制文件进行测试。我还不够大,不知道打孔卡到底是什么样子。
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{fit,positioning}
\makeatletter
\pgfmathdeclarefunction{Split}{2}{%
\begingroup%
\pgfmath@count0%
\expandafter\pgfmath@split@i#1\pgfmath@token@stop
\pgfutil@loop
\ifnum\pgfmath@count<#2\relax
\advance\pgfmath@count by1\relax
\edef\pgfmathresult{0,\pgfmathresult}%
\pgfutil@repeat
\pgfmathsmuggle\pgfmathresult%
\endgroup}
\def\pgfmath@split@i#1{%
\ifx\pgfmath@token@stop#1%
\else
\ifnum\pgfmath@count=0\relax
\edef\pgfmathresult{#1}%
\else
\edef\pgfmathresult{\pgfmathresult,#1}%
\fi
\advance\pgfmath@count by1%
\expandafter\pgfmath@split@i
\fi}
\makeatother
\begin{document}
\begin{tikzpicture}[scale=.4, transform shape]
\node[rectangle, draw, rounded corners=1ex, fit={(-1,1) (37, -11)}, line width = 0.4mm, ] (card) {};
\node[text centered, below right = 3mm and 1cm of card.north west,
font=\huge\ttfamily]
{IF WS-NUM1 IS GREATER THAN OR EQUAL TO WS-NUM2 THEN};
\foreach \x [count = \yi] in {0, ..., 79} {
\node[text centered] at (\x*.45,-11) {\x};
}
\foreach \x [count = \xi] in {0, 1, 2, ..., 79}{
% generate a random integer between 0 and 255
\pgfmathtruncatemacro{\myrnd}{random(256)-1}
% convert it to a binary
\pgfmathtruncatemacro{\myword}{bin(\myrnd)}
% convert the binary to a list and prepend zeros till it has 8 entries
\pgfmathsetmacro{\mysplitword}{Split("\myword",8)}
\foreach \k [count = \ki] in \mysplitword {
\ifnum\k=1
\path (\x*.45,-1.2*\ki)
node[text height=1.1em,draw,inner sep=0pt,minimum width={width("0")}] {};
\else
\path (\x*.45,-1.2*\ki)
node (tmp)[text height=1.1em,inner sep=0pt] {\ki}
(\tikzlastnode.north west) edge (\tikzlastnode.north east);
\fi
}
}
\end{tikzpicture}
\end{document}