マクロ展開が異常にクラッシュする

マクロ展開が異常にクラッシュする

これが私のmwe.texです

\documentclass[12pt]{report}
\usepackage{xifthen}
\usepackage{xstring}

\def\test{\textnormal{test}}

\newcounter{wordCount}
\setcounter{wordCount}{0}
\newcounter{AllWord}
\setcounter{AllWord}{0}

\NewDocumentCommand{\exy}{ m m m}{%
    \StrCount{#2}{,}[\comma]
    \StrCount{#2}{?}[\qmark]
    \ifthenelse{\qmark > 0}{%
        \addtocounter{wordCount}{\comma + \qmark}
        \addtocounter{AllWord}{\comma + \qmark}
    }{%
        \addtocounter{wordCount}{\comma + \qmark + 1}
        \addtocounter{AllWord}{\comma + \qmark + 1}
    }
    \textbf{#2} (#3), ``#1''\\%
}

\begin{document}
    \test\par
    \exy{one \test}{two \test s}{three \test s}
\end{document}

の行をコメントアウトすると\exy期待通りに動作します。そうでない場合は、次のエラーが発生します。

[{
    "resource": "/c:/Users/hsmye/LaTeX/Gaelic/vocab/mwe.tex",
    "owner": "LaTeX",
    "severity": 8,
    "message": "Undefined control sequence.\n\\reserved@a ->\\@nil",
    "source": "LaTeX",
    "startLineNumber": 27,
    "startColumn": 1,
    "endLineNumber": 27,
    "endColumn": 65536
}]

これは私のマクロの知識を超えています。誰か助けてくれませんか? これは本来の問題ではないことに注意してください。フォントの購入を必要とせずに MWE を生成するために、エラーがなくなるまで削除を続け、その後追加し直してこれを実現しました。本来の問題は次のとおりでした:

\newfontfamily{\EtGoudy}{P22 Goudy Ampersands}
\DeclareTextFontCommand{\GoudyEt}{\EtGoudy}
\newfontfamily{\cVirgi}{P22 Virginian}
\DeclareTextFontCommand{\Virgic}{\cVirgi}
\def\dispEt{\GoudyEt{c}\kern -3pt{\vspace{-0.01ex}\huge\Virgic{c}}.}
\def\Etc{\textnormal{\dispEt}}

\testを に置き換えると\Etc、同様の結果が得られます。

答え1

TeXエラーは複数行形式で表示する必要があることに注意してください。改行はメッセージを理解する上で重要であり、どれのコマンドが未定義です

! Undefined control sequence.
\reserved@a ->\@nil 
                    
l.29 ...exy{one \test}{two \test s}{three \test s}
                                                  
?

TeX プリミティブ定義を使用したため、拡張コンテキストで壊れる脆弱なコマンドが生成されました。 を使用すると、このような構造でもコマンドが安全に\NewDocumentCommandなります。\protected

これはエラーなしで実行されます


\documentclass[12pt]{report}
\usepackage{xifthen}
\usepackage{xstring}

\NewDocumentCommand\test{}{\textnormal{test}}

\newcounter{wordCount}
\setcounter{wordCount}{0}
\newcounter{AllWord}
\setcounter{AllWord}{0}

\NewDocumentCommand{\exy}{ m m m}{%
    \StrCount{#2}{,}[\comma]%%%%%%%%%%%%%%
    \StrCount{#2}{?}[\qmark]%%%%%%%%%%%%%%
    \ifthenelse{\qmark > 0}{%
        \addtocounter{wordCount}{\comma + \qmark}%%%%%%%%%%%%%%
        \addtocounter{AllWord}{\comma + \qmark}%%%%%%%%%%%%%%
    }{%
        \addtocounter{wordCount}{\comma + \qmark + 1}%%%%%%%%%%%%%%
        \addtocounter{AllWord}{\comma + \qmark + 1}%%%%%%%%%%%%%%
    }%%%%%%%%%%%%%%
    \textbf{#2} (#3), ``#1''\\%
}

\begin{document}
    \test\par
    \exy{one \test}{two \test s}{three \test s}
\end{document}

しかし、生産する

Underfull \hbox (badness 10000) in paragraph at lines 29--30

\\段落の終わりに使用すべきでない が誤って配置されているためです。 を使用する方が適切です\par

答え2

使用しませんxstring。コードの主な問題は、コマンドが\Etc(非常に) 脆弱であることです。

expl3私の提案は、テキストをコンマと疑問符で分割し、項目を数える(そして 1 を引く)ことで、それらを数えるためにを使用することです。

引数は完全に拡張され(ただし、堅牢なコマンドは拡張されません)、“精製” されるため、 などのコマンドは\textnormal表示されなくなります。

\documentclass[12pt]{report}

\newcommand\test{\textnormal{test}}
\NewDocumentCommand\dispEt{}{\GoudyEt{c}\kern -3pt{\huge\Virgic{c}}.}
\NewDocumentCommand\Etc{}{\textnormal{\dispEt}}
\newcommand\GoudyEt{}% just for testing
\newcommand{\Virgic}{}% just for testing

\newcounter{wordCount}
\newcounter{AllWord}

\ExplSyntaxOn

\NewDocumentCommand{\exy}{m m m}
 {
  \hsmyers_xyz_exy:nnen { #1 } { #2 } { \text_purify:n { \text_expand:n { #2 } } } { #3 }
 }

\int_new:N \l_hsmyers_xyz_comma_int
\int_new:N \l_hsmyers_xyz_qmark_int

\cs_new_protected:Nn \hsmyers_xyz_exy:nnnn
 {
  \hsmyers_xyz_count:nnN { , } { #3 } \l_hsmyers_xyz_comma_int
  \hsmyers_xyz_count:nnN { ? } { #3 } \l_hsmyers_xyz_qmark_int
  \int_compare:nTF { \l_hsmyers_xyz_qmark_int > 0 }
   {
    \addtocounter{wordCount}
     {
      \int_eval:n { \l_hsmyers_xyz_comma_int + \l_hsmyers_xyz_qmark_int }
     }
    \addtocounter{AllWord}
     {
      \int_eval:n { \l_hsmyers_xyz_comma_int + \l_hsmyers_xyz_qmark_int }
     }
    }{%
    \addtocounter{wordCount}
     {
      \int_eval:n { \l_hsmyers_xyz_comma_int + \l_hsmyers_xyz_qmark_int + 1}
     }
    \addtocounter{AllWord}
     {
      \int_eval:n { \l_hsmyers_xyz_comma_int + \l_hsmyers_xyz_qmark_int + 1}
     }
   }
  \textbf{#2}~#4,~``#1''
 }
\cs_generate_variant:Nn \hsmyers_xyz_exy:nnnn { nne }

\cs_new_protected:Nn \hsmyers_xyz_count:nnN
 {
  \seq_set_split:Nnn \l_tmpa_seq { #1 } { #2 }
  \int_set:Nn #3 { \seq_count:N \l_tmpa_seq - 1 }
 }

\ExplSyntaxOff

\begin{document}

\test\par

\exy{one \Etc}{two \test \Etc{} s}{three \Etc{} s}

wordCount=\the\value{wordCount}

AllWord=\the\value{AllWord}

\exy{one \test}{two, three?}{three \test s}

wordCount=\the\value{wordCount}

AllWord=\the\value{AllWord}

\end{document}

ここに画像の説明を入力してください

関連情報