将从文件内容中读取的唯一字符附加到字符串

将从文件内容中读取的唯一字符附加到字符串

我有一个从表中读取的 2 个字符串列表,例如

\begin{filecontents*}{attributetools.dat}
Attribute
SL
SK 
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}

我想创建一个包含唯一 2 个字符的字符串。结果应该是

SLSKMCAAPTUP

这是我迄今为止想到的办法。

\documentclass[10pt,a4paper]{article}
\usepackage{xparse}
\usepackage{xstring}
\usepackage{filecontents}
\usepackage{pgfplotstable}
\usepackage{ifthen}

\def\mystring{} % initialize
\def\extendmystring#1#2{\edef\mystring{#1\mystring#2}}

\begin{filecontents*}{attributetools.dat}
Attribute
SL
SK 
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}

\begin{document}

\mystring{}

\pgfplotstableread[columns={Attribute}]{attributetools.dat}\datatableA
\pgfplotstablegetrowsof{\datatableA} 
\pgfmathtruncatemacro{\RowsInTable}{\pgfplotsretval-1} 
 \foreach \k in {0,...,\RowsInTable}{
 \pgfplotstablegetelem{\k}{Attribute}\of{\datatableA}
 \def\tempstring{\pgfplotsretval}
\extendmystring{}{\tempstring}
}

Display concatenated string
\mystring


\end{document}

但每次迭代后,mystring 值都为空。

答案1

expl3

\begin{filecontents*}{\jobname.dat}
Attribute
SL
SK 
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\makestring}{om}
 {% #1 = macro to store the string in, #2 = file name
  \almic_makestring:n { #2 }
  \IfNoValueTF { #1 }
   { \str_use:N \l__almic_makestring_str }
   { \str_new:N #1 \str_set_eq:NN #1 \l__almic_makestring_str }
 }

\ior_new:N \g__almic_makestring_stream
\str_new:N \l__almic_makestring_str
\seq_new:N \l__almic_makestring_seq

\cs_new_protected:Nn \almic_makestring:n
 {
  % clear the auxiliary sequence
  \seq_clear:N \l__almic_makestring_seq
  % read the file and store the items
  \ior_open:Nn \g__almic_makestring_stream { #1 }
  \ior_str_map_inline:Nn \g__almic_makestring_stream
   {
    \seq_put_right:Nn \l__almic_makestring_seq { ##1 }
   }
  \ior_close:N \g__almic_makestring_stream
  % remove the first item
  \seq_pop_left:NN \l__almic_makestring_seq \l_tmpa_tl
  % remove the duplicates
  \seq_remove_duplicates:N \l__almic_makestring_seq
  %
  \str_set:Nx \l__almic_makestring_str { \seq_use:Nn \l__almic_makestring_seq {} }
 }

\ExplSyntaxOff

\begin{document}

\makestring{\jobname.dat}

\makestring[\test]{\jobname.dat}

\texttt{\meaning\test}

\end{document}

在此处输入图片描述

一个“经典”的实现:

\begin{filecontents*}{\jobname.dat}
Attribute
SL
SK 
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}

\documentclass{article}

\makeatletter
\newread\almic@read
\newcommand{\makestring}[2][]{% #1 = macro to store the string in, #2 = file name
  \begingroup\endlinechar=-1
  \def\almic@out{#1}%
  \let\almic@temp\@empty
  \openin\almic@read=#2\relax
  \ifeof\almic@read\else
    \read\almic@read to \almic@line % throw away the first line
    \expandafter\almic@make
  \fi
}
\newcommand{\almic@make}{%
  \loop\unless\ifeof\almic@read
    \read\almic@read to \almic@line
    \ifcsname almic@\almic@line\endcsname\else
      \expandafter\let\csname almic@\almic@line\endcsname\@empty
      \edef\almic@temp{\almic@temp\almic@line}%
    \fi
  \repeat
  \ifx\almic@out\@empty
    \almic@temp\expandafter\endgroup
  \else
    \edef\x{\endgroup\noexpand\newcommand*\expandafter\noexpand\almic@out{\almic@temp}}%
    \expandafter\x
  \fi
}
\makeatother

\begin{document}

\makestring{\jobname.dat}

\makestring[\test]{\jobname.dat}

\texttt{\meaning\test}

\end{document}

使用-shell-escapeUnix 工具:

\begin{filecontents*}{\jobname.dat}
Attribute
SL
SK
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile}

\makeatletter
\newcommand{\makestring}[2][]{%
  \CatchFileDef\almic@temp{|"tail -n +2 #2 | awk '!x[$0]++' | tr -d '\string\n'"}{}%
  \if\relax\detokenize{#1}\relax
    \almic@temp
  \else
    \@ifdefinable{#1}{\let#1\almic@temp}%
  \fi
}
\makeatother

\begin{document}

\makestring{\jobname.dat}

\makestring[\test]{\jobname.dat}
\texttt{\meaning\test}

\end{document}

https://stackoverflow.com/a/11532197/923955对于awkhttps://unix.stackexchange.com/a/180902为了tr

答案2

为了实现这一点,您不需要 pgfplotstable 以外的任何东西。

\documentclass[10pt,a4paper]{article}
\usepackage{pgfplotstable}

\begin{filecontents*}{attributetools.dat}
Attribute
SL
SK 
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}

\begin{document}

\pgfplotstableread[columns={Attribute}]{attributetools.dat}\datatableA
\pgfplotstablegetrowsof{\datatableA} 
\pgfmathtruncatemacro{\RowsInTable}{\pgfplotsretval-1} 
\foreach \k in {0,...,\RowsInTable}{
 \pgfplotstablegetelem{\k}{Attribute}\of{\datatableA}
 \ifnum\k=0
   \xdef\myLst{\pgfplotsretval}
   \xdef\mystring{\pgfplotsretval}
 \else
   \xdef\tmpElOld{0}
   \edef\newelement{\pgfplotsretval}
   \foreach \oldelement in \myLst
   {\ifx\newelement\oldelement
     % \typeout{duplicate}
      \xdef\tmpElOld{1}
     \fi}
   \ifnum\tmpElOld=0
     \xdef\myLst{\myLst,\pgfplotsretval}
     \xdef\mystring{\mystring\pgfplotsretval}
   \fi
 \fi 
}
\mystring

\end{document}

在此处输入图片描述

或者借助这个答案

\documentclass[10pt,a4paper]{article}
\usepackage{pgfplotstable}

\begin{filecontents*}{attributetools.dat}
Attribute
SL
SK 
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}
\makeatletter% from https://tex.stackexchange.com/a/260921/121799
\newcommand*{\IfStringInList}[2]{%
  \in@{,#1,}{,#2,}%
  \ifin@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\makeatother

\begin{document}

\pgfplotstableread[columns={Attribute}]{attributetools.dat}\datatableA
\pgfplotstablegetrowsof{\datatableA} 
\pgfmathtruncatemacro{\RowsInTable}{\pgfplotsretval-1} 
\foreach \k in {0,...,\RowsInTable}{
 \pgfplotstablegetelem{\k}{Attribute}\of{\datatableA}
 \ifnum\k=0
   \xdef\myLst{\pgfplotsretval}
   \xdef\mystring{\pgfplotsretval}
 \else
   \xdef\tmpElOld{0}
   \edef\newelement{\pgfplotsretval}
   \edef\tmp{\noexpand\IfStringInList{\pgfplotsretval}{\myLst}{%
   %\noexpand\typeout{duplicate-1}%
   }{%
   \noexpand\xdef\noexpand\myLst{\myLst,\pgfplotsretval}%
   \noexpand\xdef\noexpand\mystring{\mystring\pgfplotsretval}}}
   \tmp
 \fi 
}
\mystring\myLst

\end{document}

答案3

如果 2 个字符的字符串既不包含不平衡的花括号({和/或}不包含井号( )也不包含应该可见的#百分比( ),则可以进行经典的实现。%

请注意,经典 TeX 的\read-routine 仅在没有从包含不平衡/不匹配的花括号的标记的情况下才读取一行。否则,它会读取尽可能多的行,以获得一组没有不平衡/不匹配的花括号的标记。

因此,在下面的例子中,我以一种方式实现了一些东西,如果您愿意的话,您可以轻松切换到在 verbatim-catcode-régime 下读取东西。

\documentclass{article}

\begin{filecontents*}{attributetools.dat}
Attribute
SL
SK 
MC
SL
AA
PT
SK
UP
MC
\end{filecontents*}

\makeatletter
%%-----------------------------------------------------------------------------
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@exchange[2]{#2#1}%
\newcommand\UD@tempa{}%
\newcommand\UD@tempb{}%
\newread\UD@read
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%.............................................................................
%%   \UD@ExtractFirstArg{ABCDE} yields  {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields  {AB}
%%
%% !!! The argument of \UD@ExtractFirstArg must not be empty. !!!
%% You can check for emptiness via \UD@CheckWhetherNull before applying
%% \UD@ExtractFirstArg.
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
  \romannumeral0%
  \UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  { #1}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%   The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%%   <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
% \UD@GatherIfNotAlreadyPresentLoop{<write-handle>}%
%                                  {<action to perform to collection without braces when loop is finished>}%
%                                  {<strings collected so far, each string nested in braces>}%
%                                  {<strings collected/concatenated so far, each string not nested in braces>}%
%%.............................................................................
\newcommand\UD@GatherIfNotAlreadyPresentLoop[4]{%
   \ifeof#1%
     \expandafter\UD@firstoftwo
   \else
     \expandafter\UD@secondoftwo
   \fi
   {#2{#4}}%
   {%
     \immediate\read#1 to\UD@tempa
     \UD@CheckWhetherTempaInListLoop{#3}{%
        \UD@exchange{{#3}{#4}}%
     }{%
       \expandafter\UD@exchange\expandafter{%
         \romannumeral0%
         \UD@exchange{ }%
                     {\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}%
         \expandafter\UD@exchange\expandafter{\expandafter{\romannumeral0%
            \expandafter\UD@exchange\expandafter{\UD@tempa}{ #4}}}%
         {\expandafter{\romannumeral0\expandafter\UD@exchange\expandafter{\expandafter{\UD@tempa}}{ #3}}}%
       }%
     }%
     {\UD@GatherIfNotAlreadyPresentLoop{#1}{#2}}%
   }%
}%
% \UD@CheckWhetherTempaInListLoop{<list>}
\newcommand\UD@CheckWhetherTempaInListLoop[1]{%
  \UD@CheckWhetherNull{#1}{\UD@secondoftwo}{%
    \expandafter\expandafter\expandafter\def
    \expandafter\expandafter\expandafter\UD@tempb\UD@ExtractFirstArg{#1}%
    \ifx\UD@tempa\UD@tempb
      \expandafter\UD@firstoftwo
    \else
      \expandafter\UD@secondoftwo
    \fi
    {\UD@firstoftwo}%
    {\expandafter\UD@CheckWhetherTempaInListLoop\expandafter{\UD@firstoftwo{}#1}}%
  }%
}%
%%-----------------------------------------------------------------------------
%%
\immediate\openin\UD@read attributetools.dat %
\begingroup
\endlinechar=-1 %
\UD@exchange{%
  % read away the first line:
  \ifeof\UD@read\else\immediate\read\UD@read to\UD@tempa\fi
  % do the loop:
  \UD@GatherIfNotAlreadyPresentLoop{\UD@read}%
                                   {\endgroup\newcommand\mystring}%
                                   {}%
                                   {}%
}{%
  % In case you wish to have things read from file under verbatim-catcode-régime,
  % uncomment the following three lines:
  %\let\do\@makeother
  %\dospecials
  %\do\^^I% <- verbatimize horizontal tabs also.
}%
\immediate\closein\UD@read
\makeatother


\begin{document}

\show\mystring

\texttt{\string\mystring: \meaning\mystring}

\mystring

\end{document}

在此处输入图片描述

相关内容