这是一个非常具体的问题。我有一些代码,但我完全被难住了,因为它出于莫名其妙的原因无法工作。我需要找到外部文件的哪一行有一个选项卡。我使用ifthen
和xstring
包来测试所有内容。我试图让它尽可能短(但不是很短......)。
如果我只需要从给定的文件中搜索一个带有名称的选项卡,\fname
那就完全没有问题(这真的是一个最小的工作示例):
\documentclass{article}
\usepackage{ifthen}
\usepackage{xstring}
\begin{document}
\newcounter{nolines} % counter NumberOfLines
\def\fname{FileOne.txt} % define filename
OPENING \fname
\immediate\newread\file
\immediate\openin\file=\fname
\setcounter{nolines}{0}
\catcode`\^^I=11 % set tab ( ) to normal character
\loop\unless\ifeof\file % loop until end of \file
\stepcounter{nolines} % counter +1
\immediate\read\file to\fline % read a line of \file
\ifthenelse{\equal{\fline}{\par}}{% if \fline empty, very important check
Line \thenolines: emtpy
}{% if \fline not empty
\IfSubStr{\fline}{ }{% if \fline contains 'tab'
Line \thenolines: tab
}{% if \fline does not contain 'tab'
Line \thenolines: no tab.
}
}
\repeat % go back to \loop
\catcode`\^^I=10 % revert the code of tab ( )
CLOSING \fname
\immediate\closein\file
\end{document}
该命令的第二个参数\IfSubStr
是制表符!如果在运行之前复制/粘贴,请更改它。文本文件的示例:
1.This is some text.
3.Here comes a tab: !
4.And some more text.
如果您复制/粘贴,请再次将空格更改为制表符(a tab:
当然是在后面)。这将给出输出:
打开 File.txt
第 1 行:无制表符。
第 2 行:emtpy
第 3 行:制表符
第 4 行:无制表符。
第 5 行:emtpy
关闭 File.txt
这是完全正确的。但如果我必须在另一个文件中搜索文件名(此文件包含很多文件名,并且有很多“父文件”。因此手动搜索是不可能的。示例保持简单),它会突然在扫描的每一行中检测到一个制表符(而不是空行)。替换\def\fname{FileOne.txt} % define filename
为
\def\parentfile{File.txt} % define parentfile instead
\immediate\newread\parent
\immediate\openin\parent=\parentfile
\immediate\read\parent to\fname % read a line of the parentfile
\ifthenelse{\equal{\fname}{\par}}{% if \fname is empty
}{% if \fname is not emtpy
并在底部添加\end{document}
}
\immediate\closein\parent
File.txt 仅包含
FileOne.txt
这给出了意想不到的输出
打开 FileOne.txt
第 1 行:tab
第 2 行:emtpy
第 3 行:tab
第 4 行:tab
第 5 行:emtpy
关闭 FileOne.txt
这不是我想要的。如果不对“识别标签代码”进行任何更改,输出仍然不同,原因我真的不明白,也找不到(已经两天了……)
再次抱歉,问题太长,但我无法将其缩短。
答案1
这与标记化有关,与“父文件”业务无关。当您将“内部”代码放入 的参数中时\ifthenelse
,TeX 将使用当前适用的类别代码对其进行标记化。您(有效地)
\ifthenelse{\equal{\fname}{\par}}{% if \fname is empty
}{% if \fname is not emtpy
% Other stuff
\catcode`\^^I=11 % set tab ( ) to normal character
\loop\unless\ifeof\file % loop until end of \file
\stepcounter{nolines} % counter +1
\immediate\read\file to\fline % read a line of \file
\ifthenelse{\equal{\fline}{\par}}{% if \fline empty, very important check
Line \thenolines: emtpy
}{% if \fline not empty
\IfSubStr{\fline}{ }{% if \fline contains 'tab'
Line \thenolines: tab
}{% if \fline does not contain 'tab'
Line \thenolines: no tab.
}
}
\repeat % go back to \loop
\catcode`\^^I=10 % revert the code of tab ( )
}
在第二种情况下。这意味着 TeX 吸收了类别代码为 10(“空格”)的制表符,并且您的\catcode`\^^I=11
符什么也不做。您需要更改类别代码前TeX 吸收任何东西。使用辅助
\begingroup
\catcode`\^^I=11 % set tab ( ) to normal character
\gdef\mytestsystem{%
\loop\unless\ifeof\file % loop until end of \file
\stepcounter{nolines} % counter +1
\catcode`\^^I=11 % set tab ( ) to normal character
\immediate\read\file to\fline % read a line of \file
\ifthenelse{\equal{\fline}{\par}}{% if \fline empty, very important check
Line \thenolines: emtpy
}{% if \fline not empty
\IfSubStr{\fline}{ }{% if \fline contains 'tab'
Line \thenolines: tab
}{% if \fline does not contain 'tab'
Line \thenolines: no tab.
}
}
\repeat % go back to \loop
\catcode`\^^I=10 % revert the code of tab ( )
}
\endgroup
然后就可以使用,而不必担心使用时标签的性质。
正如 egreg 所说,您还需要在辅助设备内部设置选项卡的 catcode:这适用于读取文件时,因此设置适用于的标记化\fline
。
答案2
问题在于您现在将前一个代码作为的参数插入\ifthenelse
,因此类别代码的更改^^I
无效,因为一旦读入标记,类别代码就会被冻结。
将 移到\catcode`\^^I=11
新添加的 之前\ifthenelse
,或者\ifthenelse
完全避免:
\documentclass{article}
\def\apar{\par}
\newcounter{nolines} % counter NumberOfLines
\newread\parent
\newread\file
\usepackage{xstring}
\begin{document}
%\def\fname{\jobname.dat} % define filename
\def\parentfile{\jobname.fil} % define parentfile instead
\openin\parent=\parentfile\relax
\read\parent to\fname % read a line of the parentfile
\ifx\fname\apar\else
OPENING \fname
\openin\file=\fname\relax
\setcounter{nolines}{0}
\catcode`\^^I=11 % set tab to normal character
\loop\unless\ifeof\file % loop until end of \file
\stepcounter{nolines} % counter +1
\read\file to\fline % read a line of \file
\ifx\fline\apar % if \fline empty, very important check
Line \thenolines: empty
\else
\IfSubStr{\fline}{^^I}{% if \fline contains 'tab'
Line \thenolines: tab
}{% if \fline does not contain 'tab'
Line \thenolines: no tab.
}
\fi
\par
\repeat % go back to \loop
\catcode`\^^I=10 % revert the code of tab
CLOSING \fname
\closein\file
\fi
\closein\parent
\end{document}
当然,将内部循环保存在宏中将极大地改善文档的外观。
\jobname.dat
(我已将“内容文件”的文件名更改为,并将\jobname.fil
文件名文件更改为,只是为了不污染我的空间。)
这是一个带有定义的版本;我选择将类别代码设置为 12 而不是 11,如果读入的文件包含控制序列,这可能会出现问题。
\documentclass{article}
\usepackage{xstring}
\def\apar{\par}
\newcounter{nolines} % counter NumberOfLines
\newread\parent
\newread\file
\begingroup
\catcode`\^^I=12
\gdef\testfortab{%
\ifx\fname\apar\else
OPENING \fname
\openin\file=\fname
\par
\setcounter{nolines}{0}
\catcode`\^^I=12 % set tab to normal character
\loop\unless\ifeof\file % loop until end of \file
\stepcounter{nolines} % counter +1
\read\file to\fline % read a line of \file
\ifx\fline\apar % if \fline empty, very important check
Line \thenolines: empty
\else
\IfSubStr{\fline}{^^I}{% if \fline contains 'tab'
Line \thenolines: tab
}{% if \fline does not contain 'tab'
Line \thenolines: no tab.
}
\fi
\par
\repeat % go back to \loop
\fi
\catcode`\^^I=10 % revert the code of tab
CLOSING \fname
\closein\file
}
\endgroup
\begin{document}
\def\parentfile{\jobname.fil}
\openin\parent=\parentfile
\ifeof\parent\else
\read\parent to\fname % read a line of the parentfile
\testfortab
\fi
\closein\parent
\end{document}
通过将内循环包含在组中,可以避免定义主体中的\catcode`\^^I=12
和之间的混乱:只需说\catcode`\^^I=10
\begingroup\catcode`\^^I=12
而不是\catcode`\^^I=12
,并且\endgroup
而不是 放在\catcode`\^^I=10
最后。这主要取决于你真正要用 做什么\fname
。如果它的用法是本地的,就像例子中那样,它可能会更好。如果您需要使用它(或其修改版本,可能删除制表符)来输入文件,那么将循环封闭在一个组中并不是一个好主意,因为整个文件将在组内输入。
不分组的替代版本可能是
\chardef\savedtabcatcode=\catcode`\^^I
\catcode`\^^I=12
\newcommand\testfortab{%
\ifx\fname\apar\else
OPENING \fname
\openin\file=\fname\relax
\par
\setcounter{nolines}{0}
\chardef\savedtabcatcode=\catcode`\^^I
\catcode`\^^I=12 % set tab to normal character
\loop\unless\ifeof\file % loop until end of \file
\stepcounter{nolines} % counter +1
\read\file to\fline % read a line of \file
\ifx\fline\apar % if \fline empty, very important check
Line \thenolines: empty
\else
\IfSubStr{\fline}{^^I}{% if \fline contains 'tab'
Line \thenolines: tab
}{% if \fline does not contain 'tab'
Line \thenolines: no tab.
}
\fi
\par
\repeat % go back to \loop
\fi
\catcode`\^^I=\savedtabcatcode % revert the code of tab
CLOSING \fname
\closein\file
}
\catcode`\^^I=\savedtabcatcode % revert the code of tab
顺便说一句,\immediate
是用于书写,而不是用于阅读:在 前面\openin
,\read
它\closein
什么也不做。