在外部文件中搜索另一个外部文件中的文件名的选项卡(\catcode 不是问题)

在外部文件中搜索另一个外部文件中的文件名的选项卡(\catcode 不是问题)

这是一个非常具体的问题。我有一些代码,但我完全被难住了,因为它出于莫名其妙的原因无法工作。我需要找到外部文件的哪一行有一个选项卡。我使用ifthenxstring包来测试所有内容。我试图让它尽可能短(但不是很短......)。
如果我只需要从给定的文件中搜索一个带有名称的选项卡,\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什么也不做。

相关内容