Latext 排版作文纸

发布于 2026-10-20 19:51:18

image.png

鞭打着ai搞出来个用latex生成带格子的作文的代码,但是一些细节上经不起推敲,比如标点符号的断点,两个中文标点符号连续使用时应该放一个格子中。比如中英文、中文数字混排时需要让两个英文、数字占一个格子。请问该如何修改呢。ai似乎能力到这里了。

% !TeX program = xelatex
% =====================================================================
% 小学作文稿纸「套打」模板(双面稿纸,奇偶页镜像)
% 实测:纸 210×297;格 7×8mm;空行 2.48mm;
%       装订侧 20.5 / 上 24 / 外侧 14.5 / 下 19 mm;25 格 × 24 行
% 编译:xelatex zuowen.tex   (需编译两遍,remember picture 才生效)
% =====================================================================
\documentclass[twoside]{article}          % 恢复 twoside:奇偶页镜像
\usepackage{fontspec}
\usepackage{xeCJK}
\usepackage{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{eso-pic}
\usepackage{ocgx2}

% ==================== 1. 字体 ====================
\setCJKmainfont{SimSun}
\setmainfont{Source Han Serif SC}

% ==================== 2. 稿纸参数(实测值)====================
\newcommand{\cellWmm}{7}          % 格子宽
\newcommand{\cellHmm}{8}          % 格子高
\newcommand{\gapVmm}{2.48}        % 空行高
\newcommand{\marginBindingMm}{20.5}  % 装订侧:网格 → 纸边(奇数页=左侧,偶数页=右侧)
\newcommand{\marginOuterMm}{14.5}    % 外侧:网格 → 纸边
% 自洽验证:20.5 + 25×7 + 14.5 = 210 ✓
\newcommand{\marginTopMm}{24}
\newcommand{\marginBottomMm}{19}
% 自洽验证:24 + 24×8 + 25×2.48 + 19 = 297 ✓
\newcommand{\cols}{25}
\newcommand{\rows}{24}

% ==================== 3. 推导(不改)====================
\newlength{\cellW} \setlength{\cellW}{\cellWmm mm}
\newlength{\cellH} \setlength{\cellH}{\cellHmm mm}
\newlength{\gapV}  \setlength{\gapV}{\gapVmm mm}
\newlength{\marginTop}  \setlength{\marginTop}{\marginTopMm mm}
\newlength{\marginBottom}\setlength{\marginBottom}{\marginBottomMm mm}
\newlength{\marginBinding}\setlength{\marginBinding}{\marginBindingMm mm}

\newlength{\rowPitch} \setlength{\rowPitch}{\dimexpr\cellH+\gapV\relax}
\fontsize{\cellW}{\rowPitch}\selectfont

\newlength{\baselineInCell}
\setlength{\baselineInCell}{\dimexpr0.5\cellH+0.38\cellW\relax}

\newlength{\firstLineHeight}
\setbox0=\hbox{口}
\setlength{\firstLineHeight}{\ht0}

% twoside:inner = 装订侧 20.5mm(奇数页在左、偶数页在右,几何自动镜像)
\geometry{
  paperwidth=210mm,
  paperheight=297mm,
  top=\dimexpr\marginTop+\gapV-\firstLineHeight+\baselineInCell\relax,
  bottom=\marginBottom,
  inner=\marginBinding,                        % 装订侧 20.5mm
  textwidth=\dimexpr\cols\cellW\relax,         % 175mm;外侧自动 = 210-20.5-175 = 14.5mm ✓
}

\xeCJKsetup{CJKglue={\hskip 0pt plus 0pt minus 0pt}}
\xeCJKsetup{PunctStyle = plain}

\ExplSyntaxOn
\cs_set_protected:Npn \xeCJK_no_break: { \tex_penalty:D \c_zero_int }
\cs_set_protected:Npn \__xeCJK_nobreak_zero_glue: { \skip_horizontal:N \c_zero_skip }
\ExplSyntaxOff

\setlength{\topskip}{0pt}
\setlength{\parskip}{0pt}
\setlength{\parindent}{2\cellW}
\AtBeginDocument{\fontsize{\cellW}{\rowPitch}\selectfont}

% ==================== 4. 网格(非打印图层)====================
% 结构:外框两条竖线贯穿全高;水平线画出每行上下边;内部竖线只画在
% 每行的格子高度内,不穿过首行前/末行后/行间的空行 —— 空行由
% 上下横线 + 左右外框围成封闭横条,中间无竖线。
\newcommand{\drawgrid}{%
  \ifodd\value{page}%
    \def\gridXmm{\marginBindingMm}% 奇数页:网格距左边缘 20.5mm
  \else%
    \def\gridXmm{\marginOuterMm}%  偶数页:网格距左边缘 14.5mm
  \fi%
  \pgfmathsetmacro{\gridH}{\cellHmm*\rows + \gapVmm*(\rows+1)}%
  \pgfmathsetmacro{\gridW}{\cellWmm*\cols}%
  \begin{tikzpicture}[remember picture, overlay, gray, line width=0.3pt]
    % --- 外框:左右两条竖线贯穿整个网格高度(封闭所有空行)---
    \draw ($(current page.north west)+(\gridXmm mm, -\marginTopMm mm)$) -- ++(0, -\gridH mm);
    \pgfmathsetmacro{\gxR}{\gridXmm + \gridW}%
    \draw ($(current page.north west)+(\gxR mm, -\marginTopMm mm)$) -- ++(0, -\gridH mm);
    % ★★★ 在这里补充:外框的顶边和底边(形成完整矩形)★★★
    \draw ($(current page.north west)+(\gridXmm mm, -\marginTopMm mm)$) -- ++(\gridW mm, 0);
    \draw ($(current page.north west)+(\gridXmm mm, -\marginTopMm mm - \gridH mm)$) -- ++(\gridW mm, 0);
    % --- 水平行线:每行的上边线和下边线 ---
    \foreach \i in {0,...,\numexpr\rows-1\relax} {
      \pgfmathsetmacro{\gy}{\marginTopMm + \gapVmm + \i*(\cellHmm+\gapVmm)}%
      \draw ($(current page.north west)+(\gridXmm mm, -\gy mm)$) -- ++(\gridW mm, 0);
      \draw ($(current page.north west)+(\gridXmm mm, -\gy mm - \cellHmm mm)$) -- ++(\gridW mm, 0);
    }
    % --- 内部竖线:只画在每行格子内(不穿过空行)---
    \foreach \i in {0,...,\numexpr\rows-1\relax} {
      \pgfmathsetmacro{\gyT}{\marginTopMm + \gapVmm + \i*(\cellHmm+\gapVmm)}%
      \foreach \j in {1,...,\numexpr\cols-1\relax} {
        \pgfmathsetmacro{\gx}{\gridXmm + \j*\cellWmm}%
        \draw ($(current page.north west)+(\gx mm, -\gyT mm)$) -- ++(0, -\cellHmm mm);
      }
    }
  \end{tikzpicture}%
}

\newif\ifshowgrid
\showgridfalse   % 校准时打开;套打正式版改为 \showgridfalse

\AddToShipoutPictureBG{%
  \begin{ocg}[printocg=never]{网格}{grid}{1}%
  \drawgrid
  \end{ocg}%
}

% ==================== 5. 半角字符占一格 ====================
\ExplSyntaxOn
\NewDocumentCommand{\fullwidth}{m}
{ \tl_map_inline:nn {#1} { \makebox[\cellW][c]{##1} } }
\ExplSyntaxOff

% ==================== 6. 校准页(奇偶各一页)====================
\newcommand{\calibrationpage}{%
  \begingroup
  \parindent=0pt \parskip=0pt
  \foreach \r in {1,...,\rows}{%
    \noindent
    \foreach \c in {1,...,\cols}{\makebox[\cellW][c]{口}}%
    \par
  }%
  \endgroup
}

% ==================== 7. 标题 / 称呼 / 落款 / 日期 ====================
% 每个字符(含半角数字、字母、标点)一律装入一格;
% 标题居中、称呼顶格、落款/日期右对齐,均按整格计算,不错格。

\ExplSyntaxOn
\int_new:N \l_zw_n_int
\int_new:N \l_zw_lead_int   % 前导空格数(整数格)

% 前导空格:floor((25-n)/2) 格(标题居中)
\cs_new_protected:Npn \zw_lead_center:n #1
  {
    \int_set:Nn \l_zw_n_int { \tl_count:n {#1} }
    % expl3 整数表达式中 / 即截断除法;n 为奇数时向左偏半格
    \int_set:Nn \l_zw_lead_int { ( 25 - \l_zw_n_int ) / 2 }
    \skip_horizontal:n { \dimexpr \cellW * \l_zw_lead_int \relax }
  }

% 前导空格:25-n 格(右对齐,末字落在第 25 格右缘)
\cs_new_protected:Npn \zw_lead_right:n #1
  {
    \int_set:Nn \l_zw_n_int { \tl_count:n {#1} }
    \int_set:Nn \l_zw_lead_int { 25 - \l_zw_n_int }
    \skip_horizontal:n { \dimexpr \cellW * \l_zw_lead_int \relax }
  }

% 每字符占一格
\cs_new_protected:Npn \zw_cells:n #1
  { \tl_map_inline:nn {#1} { \makebox[\cellW][c]{##1} } }

% 标题:居中,独占一行
\NewDocumentCommand{\biaoti}{m}
  {
    \group_begin:
    \noindent
    \zw_lead_center:n {#1}
    \zw_cells:n {#1}
    \group_end:
    \par
  }

% 称呼:顶格,独占一行(冒号、感叹号等请写进参数里)
\NewDocumentCommand{\chenghu}{m}
  {
    \noindent
    \zw_cells:n {#1}
    \par
  }

% 落款、日期:各占一行、各自右对齐(落款在上、日期在下);
% 留空 {} 则跳过该行
\NewDocumentCommand{\luokuan}{mm}
  {
    \tl_if_empty:nF {#1}
      { \noindent \zw_lead_right:n {#1} \zw_cells:n {#1} \par }
    \tl_if_empty:nF {#2}
      { \noindent \zw_lead_right:n {#2} \zw_cells:n {#2} \par }
  }
\ExplSyntaxOff

% =====================================================================
\begin{document}
\calibrationpage        % 第 1 页(奇数页:网格在左 20.5mm)
\newpage
\calibrationpage        % 第 2 页(偶数页:网格在左 14.5mm)
\newpage

\biaoti{给妈妈的一封信}

\chenghu{亲爱的妈妈:}

您好!很久没有给您写信了,……

祝您身体健康!

1测试23测试456测试1a测试1a2测试。

测试行末的标点符号是否会换行显示,再写七个汉字。

果然换行了!再测试下标点符号是否能显示在同一个格子中:“这个引号真好看”。“《活着》”!

这里冒号应该留在上一行的呀呀呀呀呀呀呀呀呀呀:“呀呀呀”。这里的冒号和分号的断点倒是正确。

\luokuan{您的孩子 小明}{2026年10月20日}


\end{document}

查看更多

关注者
0
被浏览
42
0 个回答
暂无答案,快来添加答案吧

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览