업데이트

업데이트

편집 2:맨 아래에서 여기의 답변을 통합한 후 질문을 업데이트했습니다.{}를 사용할 때 인덱스에 대한 newcommand가 원치 않는 공백을 삽입합니다.

선택적으로 맨 페이지 섹션을 괄호 안에 제공하여 명령을 굵게 표시하는 함수를 만들었습니다.

\usepackage{xparse}
\newcommand*{\man}[2][]{%
   \textbf{#2}\IfNoValueF{#1}{(#1)}%
}

이제 이러한 명령에 대한 색인 항목도 생성할 수 있기를 원합니다. 그래서 래퍼 명령을 만들었습니다.

\newcommand*{\mani}[2][]{%
   \man[#1]{#2}%
   \index{#2@\man[#1]{#2}}%
}

그러나 때로는 동일한 형식을 사용하여 색인 항목을 생성하지만 실행 중인 텍스트에 명령을 인쇄하지 않으려는 경우가 있습니다. MWE는 다음과 같습니다.

\documentclass{memoir}
\usepackage{xparse}
\newcommand*{\man}[2][]{%
   \textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\newcommand*{\mani}[2][]{%
   \man[#1]{#2}%
   \index{#2@\man[#1]{#2}}%
}
\makeindex

\begin{document}
Only an index entry: \index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world

Command and index entry: \mani[1]{ssh-keygen}

\printindex
\end{document}

파일 output.idx에는 두 줄이 포함되어 있으며 두 번째 줄에는 추가 공백이 포함되어 있습니다. 따라서 질문은 추가 공간이 있는 이유는 무엇이며 추가 공간이 없도록 어떻게 수정할 수 있습니까?

\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man [1]{ssh-keygen}}{1}

편집 1:이 추가 공간의 결과에 대한 스크린샷을 추가했습니다. 두 개의 동일한 색인 항목이 인쇄됩니다.

이중 인덱스 항목

업데이트

제공된 솔루션에 따라 코드를 업데이트했지만 이제 이해할 수 없는 오류 메시지가 표시됩니다.

\documentclass{memoir}
\usepackage{xparse}
\makeindex
\NewDocumentCommand\man{om}{%
   \textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\makeatletter
\newcommand*{\mani}{%
   \@bsphack
   \begingroup
   \@sanitize
   \@mani
}
\newcommand*{\@mani}[2][]{%
   \man[#1]{#2}%
   \@wrindex{#2@\string\man[#1]{#2}}%
}
\makeatletter


\begin{document}
Two separate commands: \man[1]{ssh-keygen}\index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world

One command: \mani[1]{ssh-keygen}

\printindex
\end{document}

OverLeaf는 다음과 같이 말합니다.

컴파일러가 사용한 명령을 이해하는 데 문제가 있습니다. 명령의 철자가 올바른지 확인하십시오. 명령이 패키지의 일부인 경우 \usepackage{...}를 사용하여 서문에 패키지를 포함했는지 확인하세요.

로그 파일은 다음을 보고합니다.

! Missing number, treated as zero.
<to be read again> 
                   {
l.25     One command: \mani[1]{ssh-keygen}
                                          
A number should have been here; I inserted `0'.
(If you can't figure out why I needed to see a number,
look up `weird error' in the index to The TeXbook.)

답변1

이 명령은 -category-code-régime \index아래의 .tex-input 파일에서 내용을 읽고 토큰화하여 인수를 얻을 것으로 예상됩니다 . \@sanitize( \@sanitize-category-code-régime은 공백 문자, \, $, &, #, ^, _을 의미 %하며 ~범주 코드는 12(기타)입니다.) 이는 여러 가지 이유 때문입니다. 예:

  • 확장 가능한 토큰의 원치 않는 확장을 방지합니다.
  • 외부 파일에 제어 단어 토큰을 확장하지 않고 쓸 때 공백 문자 추가를 방지합니다.

그러나 귀하의 명령을 사용하면 \mani명령 \index의 인수가 에서 전달됩니다 \mani. \maniGathers/composes \index의 인수 인 경우 해당 인수를 구성하는 토큰은 \@sanitize-category-code-régime에서 토큰화되지 않지만 일반 Category-code-régime에서는 토큰화됩니다.

일반적인 카테고리 코드 제도 하에서 토큰화하는 것은 다음과 같은 문구가 문자 시퀀스 가 \man​​아닌 제어 단어 토큰으로 토큰화된다는 것을 의미합니다 . 제어 단어 토큰이 확장되지 않은 상태로 텍스트 파일(예: 인덱스 생성 프로세스에 속하는 일부 파일)에 기록되면 공백 문자가 추가됩니다. 즉, 문자 순서 , , , 가 기록됩니다.\man.idx\man⟨space character⟩

정의 내에서 명령을 \mani적용하여 일련의 문자 토큰으로 변환할 수 있습니다. (이로써 카테고리 코드가 0(escape)인 하나의 입력 문자에만 의존하고 정수 매개변수의 값은 TeX 엔진의 내부 문자 인코딩 체계에서 해당 문자의 코드 포인트 수와 동일합니다. 일반적으로 백슬래시 문자 는 범주 코드 0(escape)의 유일한 문자이며 일반적으로 TeX 엔진의 내부 문자 인코딩 체계에서 백슬래시 문자의 코드 포인트 번호인 92를 갖습니다.\string\man\escapechar\\escapechar

\documentclass{memoir}
\usepackage{xparse}
\NewDocumentCommand{\man}{om}{%
   \textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\NewDocumentCommand{\mani}{om}{%
   \IfNoValueTF{#1}{%
      \man{#2}%
      \index{#2@\string\man{#2}}%
    }{%
      \man[#1]{#2}%
      \index{#2@\string\man[#1]{#2}}%
    }%
}%
\makeindex

\begin{document}

Only an index entry: \index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world

Command and index entry: \mani[1]{ssh-keygen}

Only an index entry: \index{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}
Hello world

Command and index entry: \mani{ssh-keygen-no-optional-argument}

\printindex
\end{document}

위의 예에서 결과 .idx 파일은 다음과 같습니다.

\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}

\index이 접근 방식을 사용하면 매크로를 통해 제공되는 인수 내에서 "문자열화된" 유일한 항목은 \mani구문입니다 \man.

\mani의 첫 번째 또는 두 번째 인수 에서 나오는 항목은 문자열화되지 않습니다. 이러한 인수를 통해 제공된 토큰 세트에 제어 단어 토큰도 포함되어 있는 경우 여기에도 원하지 않는 공백이 생길 수 있습니다.

인수 내에서 각 토큰에 \StringifyNAct적용되는 루틴을 제공할 수 있습니다 .\string

\StringifyNAct{⟨action⟩}{⟨token 1⟩⟨token 2⟩...⟨token n⟩}

수익률:

⟨action⟩{⟨stringification of token 1⟩}%
⟨action⟩{⟨stringification of token 2⟩}%
...
⟨action⟩{⟨stringification of token n⟩}%

\string여기서 "토큰의 문자열화"는 해당 토큰에 적용한 결과를 의미합니다 . -확장
으로 인해 \romannumeral두 개의 확장 단계(예: 두 개의 \expandafter-체인을 통해)를 트리거하여 결과가 전달됩니다.

나는 일반적인 카테고리 코드 규정 하에서 인수를 읽고 토큰화하는 명령을 제안 \mani하지만, 공백 문자(그리고 아마도 ^^ITeX의 - ^^표기법으로 주소 지정이 가능한 가로 탭 문자도 가능)는 카테고리 코드 12(기타)입니다. ), \StringifyNAct인수에 적용한 다음 그 결과를 \index-command에 전달하고 중첩된 \scantokens-command에 전달합니다 \man.

\documentclass{memoir}

\makeatletter
%%========================Code for \StringifyNAct==============================
%%
%% Copyright (C) 2019, 2020 by Ulrich Diez ([email protected])
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public Licence (LPPL), either
%% version 1.3 of this license or (at your option) any later
%% version. (The latest version of this license is in:
%% http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included
%% documentation nor for any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo,
%%    \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%%    \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%%    \UD@CheckWhetherLeadingSpace, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% 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}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
  {\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\newcommand\UD@CheckWhetherLeadingSpaceB{}%
\long\def\UD@CheckWhetherLeadingSpaceB#1 {%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%%   \UD@ExtractFirstArg{ABCDE} yields  {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields  {AB}
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
  \romannumeral0%
  \UD@ExtractFirstArgLoop{#1UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  { #1}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%-----------------------------------------------------------------------------    
%% In case an argument's first token is an opening brace, stringify that and
%% add another opening brace before that and remove everything behind the 
%% matching closing brace:
%% \UD@StringifyOpeningBrace{{Foo}bar} yields {{Foo}  whereby the second
%% opening brace is stringified:
%%.............................................................................
\newcommand\UD@StringifyOpeningBrace[1]{%
  \romannumeral0%
  \expandafter\UD@ExtractFirstArgLoop\expandafter{%
    \romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
    \expandafter\expandafter
    \expandafter            {%
    \expandafter\UD@firstoftwo
    \expandafter{%
    \expandafter}%
    \romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
    \expandafter\string
    \expandafter}%
    \string#1%
  UD@SelDOm}%
}%
%%-----------------------------------------------------------------------------    
%% In case an argument's first token is an opening brace, remove everything till 
%% finding the corresponding closing brace. Then stringify that closing brace:
%% \UD@StringifyClosingBrace{{Foo}bar} yields: {}bar} whereby the first closing
%% brace is stringified:
%%.............................................................................
\newcommand\UD@StringifyClosingBrace[1]{%
   \romannumeral0\expandafter\expandafter\expandafter
                 \UD@StringifyClosingBraceloop
                 \UD@ExtractFirstArg{#1}{#1}%
}%
\newcommand\UD@CheckWhetherStringifiedOpenBraceIsSpace[1]{%
%% This can happen when character 32 (space) has catcode 1...
  \expandafter\UD@CheckWhetherLeadingSpace\expandafter{%
    \romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
    \expandafter\UD@secondoftwo
    \expandafter{%
    \expandafter}%
    \expandafter{%
    \romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
    \expandafter\UD@firstoftwo
    \expandafter{%
    \expandafter}%
    \romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
    \expandafter\string
    \expandafter}%
    \string#1%
  }%
}%
\newcommand\UD@TerminateStringifyClosingBraceloop[2]{%
  \UD@Exchange{ }{\expandafter\expandafter\expandafter}%
  \expandafter\expandafter
  \expandafter{%
  \expandafter\string      
  \romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
  \expandafter#1%
  \string#2%
  }%
}%
\newcommand\UD@StringifyClosingBraceloopRemoveElement[4]{%
  \expandafter\UD@PassFirstToSecond\expandafter{\expandafter
  {\romannumeral0\expandafter\UD@secondoftwo\string}{}%
    \UD@CheckWhetherStringifiedOpenBraceIsSpace{#4}{%
      \UD@Exchange{\UD@removespace}%
    }{%
      \UD@Exchange{\UD@firstoftwo\expandafter{\expandafter}}%
    }{%
      \UD@Exchange{ }{\expandafter\expandafter\expandafter}%
      \expandafter#1%
      \romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
      \expandafter
    }%
    \string#4%
  }{\expandafter\UD@StringifyClosingBraceloop\expandafter{#2#3}}%
}%
\newcommand\UD@StringifyClosingBraceloop[2]{%
  \UD@CheckWhetherNull{#1}{%
    \UD@CheckWhetherStringifiedOpenBraceIsSpace{#2}{%
      \UD@TerminateStringifyClosingBraceloop{\UD@removespace}%
    }{%
      \UD@TerminateStringifyClosingBraceloop{\UD@firstoftwo\expandafter{\expandafter}}%
    }%
    {#2}%
  }{%
    \UD@CheckWhetherLeadingSpace{#1}{%
      \UD@StringifyClosingBraceloopRemoveElement
      {\UD@removespace}{\UD@removespace}%
    }{%
      \UD@StringifyClosingBraceloopRemoveElement
      {\UD@firstoftwo\expandafter{\expandafter}}{\UD@firstoftwo{}}%
    }%
    {#1}{#2}%
  }%
}%
%%-----------------------------------------------------------------------------    
%% Apply <action> to the stringification of each token of the argument:
%%
%% \StringifyNAct{<action>}{<token 1><token 2>...<token n>}
%%
%% yields:  <action>{<stringification of token 1>}%
%%          <action>{<stringification of token 2>}%
%%          ...
%%          <action>{<stringification of token n>}%
%%
%% whereby "stringification of token" means the result of applying \string
%% to the token in question.
%% Due to \romannumeral-expansion the result is delivered after two
%% \expandafter-chains.
%% If you leave <action> empty, you can apply a loop on the list formed by
%%   {<stringification of token 1>}%
%%   {<stringification of token 2>}%
%%   ...
%%   {<stringification of token n>}%
%%
%% Below a macro \ConcatenateStringifiedtokens is implemented which loops
%% on that list for concatenating.
%%.............................................................................
\newcommand\StringifyNAct{%
  \romannumeral0\StringifyNActLoop{}%
}%
%%.............................................................................
%% \StringifyNActLoop{{<stringification of token 1>}...{<stringification of token k-1>}}%
%%                   {<action>}%
%%                   {<token k>...<token n>}
%%.............................................................................
\newcommand\StringifyNActLoop[3]{%
  \UD@CheckWhetherNull{#3}{%
    \UD@firstoftwo{ }{}#1%
  }{%
    \UD@CheckWhetherBrace{#3}{%
      \expandafter\expandafter\expandafter\UD@Exchange
      \expandafter\expandafter\expandafter{%
        \UD@StringifyClosingBrace{#3}%
      }{%
        \expandafter\StringifyNActLoop\expandafter{%
          \romannumeral0%
          \expandafter\expandafter\expandafter\UD@Exchange
          \expandafter\expandafter\expandafter{\UD@StringifyOpeningBrace{#3}}{\StringifyNActLoop{#1}{#2}}%
        }{#2}%
      }%
    }{%
      \UD@CheckWhetherLeadingSpace{#3}{%
        \expandafter\UD@PassFirstToSecond\expandafter{\UD@removespace#3}{%
          \StringifyNActLoop{#1#2{ }}{#2}%
        }%
      }{%
        \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#3}{%
          \expandafter\StringifyNActLoop\expandafter{%
             \romannumeral0%
             \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\UD@PassFirstToSecond
             \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{%
               \expandafter\expandafter\expandafter\string
               \expandafter\UD@Exchange
               \romannumeral0\UD@ExtractFirstArgLoop{#3UD@SelDOm}{}%
             }{ #1#2}%
          }%
          {#2}%
        }%
      }%
    }%
  }%
}%
%% The promised loop for concatenating stringified tokens - apply as:
%%
%%      \romannumeral0%
%%      \expandafter\expandafter\expandafter
%%      \ConcatenateStringifiedtokens
%%      \StringifyNAct{}{<tokens to stringify>}\relax
%%
\newcommand*\ConcatenateStringifiedtokens{%
  \ConcatenateStringifiedtokensloop{ }%
}%
\newcommand\ConcatenateStringifiedtokensloop[2]{%
  \ifx\relax#2\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {#1}{%
    \ConcatenateStringifiedtokensloop{#1#2}%
  }%
}%
%%=================== End of code for \StringifyNAct ==========================
\makeatother

\usepackage{xparse}

\makeatletter
\NewDocumentCommand{\man}{om}{%
   \UD@CheckWhetherNull{#2}{}{%
     \toks@{#2}%
     \textbf{\the\toks@}%
   }%
   \IfNoValueF{#1}{(#1)}%
}%
\NewDocumentCommand{\mani}{}{%
  \begingroup
  \catcode`\ =12\relax
  \catcode`\^^I=12\relax
  \maniinner
}%
\NewDocumentCommand{\maniinner}{om}{%
   \endgroup
   \IfNoValueTF{#1}{%
      \expandafter\maniinnerinner\expandafter{%
        \romannumeral0%
        \expandafter\expandafter\expandafter
        \ConcatenateStringifiedtokens
        \StringifyNAct{}{#2}\relax
      }%
    }{%
      \expandafter\UD@PassFirstToSecond\expandafter{%
        \romannumeral0%
        \expandafter\expandafter\expandafter
        \ConcatenateStringifiedtokens
        \StringifyNAct{}{#2}\relax
      }{%
        \expandafter\maniinnerinner\expandafter[\expandafter{%
          \romannumeral0%
          \expandafter\expandafter\expandafter
          \ConcatenateStringifiedtokens
          \StringifyNAct{}{#1}\relax
        }]%
      }%
    }%
}%
\makeatother
\begingroup
\newcommand\maniinnerinner[1]{%
  \endgroup
  \NewDocumentCommand{\maniinnerinner}{om}{%
     \IfNoValueTF{##1}{%
        \scantokens{\man{##2}#1}%
        \index{##2@\string\man{##2}}%
      }{%
        \scantokens{\man[##1]{##2}#1}%
        \index{##2@\string\man[##1]{##2}}%
      }%
  }%
}%
\catcode`\%=12\relax
\maniinnerinner{%}%

\makeindex

\begin{document}

Only an index entry: \index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world

Command and index entry: \mani[1]{ssh-keygen}

Only an index entry: \index{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}
Hello world

Command and index entry: \mani{ssh-keygen-no-optional-argument}

\newcommand\ke{ke}%
\newcommand\one{1}%

Only an index entry: \index{ssh-\ke y\string#gen@\man[\one]{ssh-\ke y\string#gen}}
Hello world

Command and index entry: \mani[\one]{ssh-\ke y\string#gen}


\printindex
\end{document}

위의 예에서 결과 .idx 파일은 다음과 같습니다.

\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}
\indexentry{ssh-\ke y\string#gen@\man[\one]{ssh-\ke y\string#gen}}{1}
\indexentry{ssh-\ke y\string#gen@\man[\one]{ssh-\ke y\string#gen}}{1}

답변2

\writememoir가 있는 .idx 파일에 사용되는 -handle 의 이름은 \writeLaTeX 2ε-macro와 함께 사용되는 -handle 의 이름과 다릅니다 \@wrindex.

\write따라서 인덱스의 "kernel--handle" 이름을 \write인덱스의 "memoir--handle"에 매핑해야 합니다.

\documentclass{memoir}
\usepackage{xparse}
\makeindex
\NewDocumentCommand\man{om}{%
   \textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\makeatletter
\newcommand*{\mani}{%
   \@bsphack
   \begingroup
   \@sanitize
   \@mani
}
\NewDocumentCommand{\@mani}{om}{%
   \@ifundefined{@indexfile}{%
     \expandafter\let\expandafter\@indexfile\csname\jobname @idxfile\endcsname
   }{}%
   \IfNoValueTF{#1}{%
     \man{#2}%
     \@wrindex{#2@\string\man{#2}}%
   }{%
     \man[#1]{#2}%
     \@wrindex{#2@\string\man[#1]{#2}}%
   }%
}
\makeatletter

\begin{document}
Two separate commands: \man[1]{ssh-keygen}\index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world

One command: \mani[1]{ssh-keygen}

\printindex
\end{document}

.idx 파일은 다음과 같습니다.

\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}

다른 답변에 제시된 토큰화 후 문자열화 접근 방식과 달리 인수에 control-symbol-token 및/또는 control-symbol-token이 포함되는 \@sanitize경우 중괄호 균형을 처리하지 않습니다 .\mani\{\}

관련 정보