雾月
雾月
这家伙很懒,什么也没写!

注册于 5年前

回答
253
文章
2
关注者
25

最简单的办法是加上这行

\pgfkeys{...
  /mycmd/.search also={/tikz}, % <- 自动找 /tikz/...
}
\documentclass{article}
\usepackage{tikz}

\pgfkeys{%
  /mycmd/.is family,
  /mycmd/.cd,
  /mycmd/.search also={/tikz},
  default/.style={color=black},
  color/.store in = \mycmdcolor,
}

\pgfkeys{%
  /tikz/mycmd/.code args={#1}{%
    \pgfkeys{/mycmd, default, #1}
    \pgfkeysalso{color=\mycmdcolor,}
  }
}

\newcommand{\mydraw}[1][]{%
\draw[mycmd={#1}] (0,0) -- (4,0); }

\begin{document}
\begin{tikzpicture}
  \mydraw[color=blue, line width=1mm]
\end{tikzpicture}
\end{document}

\documentclass[tikz,border=5pt]{standalone}
\usepackage{tkz-euclide}

\ExplSyntaxOn\makeatletter
\pgfmathdeclarefunction{pointveclen}{3}{
  \begingroup
  \tikz@scan@one@point\pgfutil@firstofone(#1)\relax
    \pgf@xx\pgf@x \pgf@xy\pgf@y
  \tikz@scan@one@point\pgfutil@firstofone(#2)\relax
    \pgf@yx\pgf@x \pgf@yy\pgf@y
  \pgfmathparse{veclen(\the\pgf@xx+#3\the\pgf@yx,\the\pgf@xy+#3\the\pgf@yy)}
  \pgfmath@smuggleone\pgfmathresult
  \endgroup
}
\NewDocumentCommand\tkzAutoLabelPolygons{O{} r()} {
  \group_begin:
  \seq_gclear:N \g_tmpa_seq
  \foreach \x in {#2} { \seq_gput_right:Ne \g_tmpa_seq { \x } }
  \seq_get_left:NN \g_tmpa_seq \l_tmpa_tl
  \seq_get_right:NN \g_tmpa_seq \l_tmpb_tl
  \seq_gput_left:NV \g_tmpa_seq \l_tmpb_tl
  \seq_gput_right:NV \g_tmpa_seq \l_tmpa_tl
  \int_step_inline:nnn { 2 } { \seq_count:N \g_tmpa_seq - 1 }
    {
      \seq_gpop_left:NN \g_tmpa_seq \l_tmpa_tl
      \tl_set:Ne \l_tmpb_tl { \seq_item:Nn \g_tmpa_seq { 1 } }
      \tl_set:Ne \l_tmpc_tl { \seq_item:Nn \g_tmpa_seq { 2 } }
      \pgfinterruptboundingbox
      \coordinate (tempa) at ($1cm/pointveclen("\l_tmpa_tl","\l_tmpb_tl","-")
        *($(\l_tmpa_tl)-(\l_tmpb_tl)$)$);
      \coordinate (tempb) at ($1cm/pointveclen("\l_tmpc_tl","\l_tmpb_tl","-")
        *($(\l_tmpc_tl)-(\l_tmpb_tl)$)$);
      \coordinate (tempc) at ($0.3*1cm/pointveclen("tempa","tempb","+")
        *($(tempa)+(tempb)$)$);
      \endpgfinterruptboundingbox
      \path (\l_tmpb_tl) -- ($(\l_tmpb_tl)-(tempc)$)
        node[label~style,anchor=center,#1] {$\l_tmpb_tl$};
    }
  \group_end:
}
\ExplSyntaxOff\makeatother

\begin{document}

\begin{tikzpicture}
  \tkzDefPoints{-1/-1/A, 1/-2/B, 3/0/C, 2/4/D, 0/5/E,-3/2/F}  
  \tkzDrawPolygons[thick](A,...,F)
  \tkzAutoLabelPolygons(A,...,F)
\end{tikzpicture}

\begin{tikzpicture}
  \tkzDefPoints{-1/-1/A, 1/-2/B, 0.5/0/C, 2/4/D, 0/5/E,-3/2/F}
  \tkzDrawPolygons[thick](A,...,F)
  \tkzAutoLabelPolygons(A,...,F)
\end{tikzpicture}

\end{document}

image.png

见 The TeXBook 第 258 页(2021 年版),The LaTeX Companion 第三版 5.3.4、5.3.5 节。

TeX 遇到某些内容和输出这些内容所在的页码并不一定相同,比如,TeX 在准备第 5 页所需的内容时遇到太多文字,直到第 5 页输出完成后才能知道哪些文字是多余的,然而它们是在第 5 页中发现的,却并不是在第 5 页输出的,这就存在某些问题,比如假如这些多出来的文字中获取了 page 计数器的值,由于它在第 5 页中执行,得到的结果是 5,而不是 6。TeX 为了解决这个问题提供了几个方案,一个是把要获取的这些值延迟到页面输出完成之后再获取,另一个就是 mark 机制。

firstmark 就是输出的那一页最开始遇到的 mark,botmark 就是最后遇到的 mark,topmark 就是上一页的 botmark。最开始的 TeX 只有一个 mark 类,e-TeX 扩展为了 32767 个。

如果你用 LaTeX 2022-06-01 及之后的版本,那么 LaTeX 提供了 \FirstMark \LastMark \TopMark,并且不但能获得当前页的,还能获得上一页、当前栏、上一栏的。建议使用这些命令。如果用的是 2025-06-01 的版本,还能获得 multicols 每一栏的 marks。

不过,如果 marks 出现在其它盒子中,那么 TeX 无法正确更新,可以用我写的 updatemarks 宏包。

\changetext 的修改是局部的,而 shipout 钩子总是放在一个组中执行,必须要全局修改。

\AddToHookNext{shipout}{\global\advance\textheight2cm\relax}

不过,如果修改 \textheight 正好发生在 paracol 环境中间,是无效的,原因未知。

设置 TEXINPUTS 环境变量,.tex .sty 这类文件都在 $TEXMF/tex// 目录里查找,而 TeX 文档的位置在 $TEXDOCS$TEXMF/doc//) 这个变量里(texmf.cnf 的变量,不是环境变量)。

cmd:
set TEXINPUTS=;$TEXDOCS

powershell:
$env:TEXINPUTS=';$TEXDOCS'

不过最好不要设置 $TEXDOCS 来编译文档,因为这里的目录包含许多配置文件(比如 hyperref.cfg,你设置上面的环境变量再用 xelatex 编译就会发现报错),会出现什么完全不能预测。
可以先修改 TEXINPUTS 然后用 kpsewhich 找到所需的文件,只用特定目录一般问题不大:

set TEXINPUTS=;$TEXDOCS
kpsewhich lshort-zh-cn-style.sty
% 注意要先清除
set TEXINPUTS=
set TEXINPUTS=;$TEXMFDIST/doc/latex/lshort-chinese//
xelatex main.tex

可以查看 texdoc kpathsea 文档了解更多内容。

xecjk 会在 cjk 文字之间插入 \CJKglue,这个值一般为 \hskip 0pt plus 0.08\baselineskip,这个 stretch 比较小,一般小于 1em,在宽度为 3em 时,两个汉字间需要插入的空白大于 cjkglue 的伸长部分,所以会报 warning。

英文空格会变成一个 glue,根据需要会使用 \spaceskip\xspaceskip;xecjk 的中文与西文之间会插入 \CJKecglue,都可以用于控制所插入的空白的 stretch 和 shrink。

CJKfilltwosides 就调整了 \CJKglue,使得空白可以无限伸长。

X-Y problem?
你想要的是在两个字符中间插入任何东西,只要这些字符连同它中间的东西一共是三个字符的宽度就行?还是要保证不论输入几个字符,总宽度固定就行?还是不论输为何,其最终结果是两个汉字,然后在两个汉字中间插入 \quad?还是就是给定两汉字,中间插入 \quad

这几个问题难度不同,解决办法可以说是完全不同。最简单就是第四个,这种你可以直接写 \newcommand\mycmd[2]{#1\quad#2}\mycmd 余华。对于第一个问题还可以还可以看 xecjk 的文档,它有分散对齐汉字的环境。

无需任何宏包:

\documentclass{article}

\makeatletter
\def\@zheng@i{\vrule height2ex depth-1.8ex width2ex\relax} % U+1D372
\def\@zheng@ii{\@zheng@i\kern-2ex\hbox to2ex
  {\hfil\vrule height2ex depth-.2ex width.2ex\hfil}} % U+1D373
\def\@zheng@iii{\@zheng@ii\kern-1ex\hbox to1ex
  {\vrule height1.1ex depth-0.9ex width0.8ex\hfil}} % U+1D374
\def\@zheng@iv{\@zheng@iii\kern-2ex\hbox to2ex
  {\hskip 0.3ex\vrule height1.3ex depth-0.2ex width0.2ex\hfill}} % U+1D375
\def\@zheng@v{\@zheng@iv\kern-2ex\vrule height0.2ex width2ex\relax} % U+1D376
\protected\def\@zheng#1{%
  \edef\x{\ifcase#1 \or\noexpand\@zheng@i\or\noexpand\@zheng@ii\or\noexpand\@zheng@iii
    \or\noexpand\@zheng@iv\or\unexpanded{\@zheng@format{\@zheng@v}}%
    \else\unexpanded{\@zheng@format{\@zheng@v}\zheng{#1-5}}\fi}\x}
\protected\def\zheng#1{\leavevmode\expandafter\@zheng\expandafter{\the\numexpr#1}}
\long\def\@zheng@format#1{\mbox{#1}\ }
\protected\long\def\zhengformat#1{\long\def\@zheng@format##1{#1}}
\makeatother

\begin{document}

12345 \zheng{1} \zheng{2} \zheng{3} \zheng{4} \zheng{5}

12345 \zheng{1}\zheng{2}\zheng{3}\zheng{4}\zheng{5}

6 \zheng{6}

horizontal 42:
\zhengformat{\mbox{#1}\ }
\zheng{42}

vertical 42:
\zhengformat{\mbox{#1}\\}
\begin{tabular}[t]{c}
\zheng{42}
\end{tabular}

\end{document}

image.png

有的字体比如 Noto Unicode、霞骛文楷、Plangothic P1 等有这些字形,下载这些字体后直接用 \fontspec{..} \symbol{"1D372} 即可。

\documentclass[UTF8]{ctexart}%pdflatex编译
\usepackage[showframe,margin=1in]{geometry}
\usepackage{enumitem}
    \setlist[enumerate]{nosep,labelsep=0pt,leftmargin=2em}
\usepackage{multicol}
    \setlength{\columnseprule}{.4pt}
    \setlength{\columnsep}{1cm}

\makeatletter
\newcommand\brule[3][\z@]{\leavevmode
  {\setlength\@tempdima{#2}\setlength\@tempdimb{#1}\setlength\@tempdimc{#3}%
   \@tempcnta=\fpeval{ceil(\@tempdima/5pt)}
   \kern\z@
   \loop\ifnum\@tempcnta>\z@
     \vrule \@width 5pt \@height \@tempdimc \@depth -\@tempdimb \hskip\z@skip
     \advance\@tempcnta\m@ne
   \repeat \unskip
}}
\makeatother
\begin{document}

\noindent\textbf{16. }补写出下列句子中的空缺部分。(6分)

\begin{multicols}{2}

\begin{enumerate}[label=(\arabic{enumi})]
    \item 
    王湾《次北固山下》的名句“\brule{9em}{.4pt},\brule{9em}{.4pt}”,描写时序交替中的景物,暗示着时光流逝,蕴含着自然理趣。
    \item 
    小慧为朋友家的农家乐餐厅写宣传横幅,直接使用了陆游《游山西村》里的“\brule{9em}{.4pt},\brule{9em}{.4pt}”两句诗,朋友看了觉得很贴切。
    \item 
    行至群山深处,见到一挂瀑布飞泻而下,水石激荡,轰鸣作响,于老师回头对学生们说:“这不就是古诗中写的‘\brule{9em}{.4pt},\brule{9em}{.4pt}’嘛!”
\end{enumerate}

\end{multicols}

\noindent\textbf{参考答案:}

\begin{enumerate}[label=(\arabic{enumi})]
    \item 
    海日生残夜\quad 江春入旧年
    \item 
    山重水复疑无路\quad 柳暗花明又一村
    \item 
    飞流直下三千尺\quad 疑是银河落九天(飞湍瀑流争喧豗\quad 砯崖转石万壑雷)
\end{enumerate}

\end{document}

image.png

略微改进版:

\newcommand\brule[3][\z@]{\leavevmode
  {\setlength\@tempdima{#2}\setlength\@tempdimb{#1}\setlength\@tempdimc{#3}%
   \@tempcnta=\fpeval{ceil(\@tempdima/5pt)} \@tempdima=\dimexpr5pt/\@tempcnta\relax\relax
   \ifnum\@tempcnta>\z@
     \loop\ifnum\@tempcnta>\z@
       \vrule \@width 5pt\@height\@tempdimc \@depth-\@tempdimb \hskip\z@\@minus\@tempdima\relax
       \advance\@tempcnta\m@ne
     \repeat
   \unskip\fi
}}

  1. 这是手动创建命令钩子,如果命令钩子不存在,在向此钩子添加代码时,会执行自动修补。所以,为了不让它执行自动修补,必须创建钩子。我贴的图片没有加上创建钩子的代码,需要补充。
  2. 随便在哪用都行。
  3. 见 1。

image.png

使用尾递归即可,这是比较常见的处理方式,\tl_map_.. 也是用尾递归实现的。

\documentclass{article}
\ExplSyntaxOn
\cs_new:Npn \__MyCMD_deal:n #1
  {
    output: #1 \par %伪应用
  }

\quark_new:N \q__MyCMD_stop
\NewDocumentCommand{\__MyCMD_deal_newversion:nw}{+m+O{}}
  {
    \tl_if_eq:nnF {#1} { \q__MyCMD_stop }
      {
        output: #1 ~ option: #2 \par %伪应用
        
        \__MyCMD_deal_newversion:nw
      }
  }
\NewDocumentCommand{\MyCMD}{+m}
  {
    \__MyCMD_deal_newversion:nw #1 \q__MyCMD_stop []
  }
\ExplSyntaxOff

\begin{document}
\MyCMD{{par 1}{par 2}{par 3}}

\MyCMD{{par 1}{par 2}}

\MyCMD{{par 1}[opt 1]{par 2}[opt 2]{par 3}[opt 3]}

\MyCMD{{par 1}[opt 1]{par 2}{par 3}[opt 3]}

\MyCMD{{par 1}[opt 1]{par 2}[opt 2]}

\MyCMD{{par 1}{par 2}[opt 2]{par 3}}
\end{document}

由于不需要可展的实现,可以用 \tl_if_eq:nn 比较,无需可展的 \quark_if_..,这样更快。

这三个命令在文档中说的是可以用在处理键的代码中,在其它地方使用显然是未定义行为。包括那些 undocumented 命令,都由使用者自己负责。

首先,context 没有你给的那些命令行参数。
其次,TeXLive 2025 的 ConTeXt 默认用的是 LuaMetaTeX,它不带 kpathsea 库,所有的第三方模块都必须手动安装(包括 tikz、pgfplots 等),否则就会找不到相关文件,用 LuaTeX 的版本才行。因为我没有 TeX Studio,不知道你是如何成功编译的。不过你可以查看输出的 PDF 文件,看看究竟是哪个版本。
最后,LaTeX Workshop 需要找到主文件(即 root file,见 https://github.com/James-Yu/LaTeX-Workshop/wiki/Compile#the-root-file),主要是找到 \documentclass 这个命令,这在 ConTeXt 中是没有的。

只要解决上面这三个问题就行了。
修改 setting.json

{
    "latex-workshop.latex.tools": [
        {
            "name": "context-luatex",
            "command": "context",
            "args": [
                "--synctex",
                "--nonstopmode",
                "--luatex",
                "%DOC%"
            ],
            "env": {}
        },
    ],
    "latex-workshop.latex.recipes": [
        {
            "name": "context (luatex)",
            "tools": [
                "context-luatex"
            ]
        },
    ]
}

然后用 magic comment 设置主文件(注意第一行):

% !TEX root = main.tex
%命令行编译: context --luatex main
\usemodule[tikz]
\startTEXpage[offset=2pt]
\def\mygrid#1{
    \fill [gray!60]     (0,0) rectangle (#1,#1);
    \draw [white,thick] (0,0) grid      (#1,#1);
    \foreach \x in {1,...,#1}
    {
        \node at (0,\x) [left]       {$\x$};
        \node at (\x,0) [below]      {$\x$};
    }
        \node at (0,0)  [below left] {$0$};
}
\starttikzpicture[every node/.append style={scale=.5}]
\mygrid{3}
\stoptikzpicture

\CONTEXT{} -- \LUATEX

\stopTEXpage

然后点击 context (luatex) 即可。
image.png

可能是 xetex 的驱动文件有问题。asymptote 支持输出为 PDF,用 PDF 文件就好了。

发布
问题