
単純なMATLABファイルの最初の行を抽出する方法そしてその直後の行は%
? という文字で始まります。抽出する行数は不明です。次に、 を使ってlistingsutf8
抽出したコードを表示したいと思います。
matlab ファイルの例:
function myfunction(args)
% Comments
% about the function
% with an unknown number of lines
command1(); % another comment
command2();
% another comment
command3();
end
抽出する行:
function myfunction(args)
% Comments
% about the function
% with an unknown number of lines
答え1
これは比較的難解な内部マクロの組み合わせで実行できますlistings
。外部ファイルに書き込む必要はありません。便宜上、 という新しいブール キーを定義しましたonlyheader
。このキーが設定されている場合、最初の連続したコメント行ブロック (つまり、関数ヘッダー) の後の出力はすべて削除されます。
編集: この機能は、バージョン0.2matlab-prettifier
と呼ばれるキーを介してmlonlyheader
。
\documentclass{article}
\usepackage[T1]{fontenc}
% --- write to file ---
\usepackage{filecontents}
\begin{filecontents*}{code.txt}
function myfunction(args)
%MYFUNCTION One-line description goes here
% Comments
% about the function
% with an unknown number of lines
[ 2 3 4 ]
command1(); % another comment
command2();
% another comment
command3();
end
\end{filecontents*}
\usepackage[framed]{matlab-prettifier}
\lstset{style = Matlab-editor}
\begin{document}
\lstinputlisting
[caption = {\texttt{mlonlyheader=false}}]
{code.txt}
\lstinputlisting
[
caption = {\texttt{mlonlyheader=true}},
mlonlyheader = true,
]{code.txt}
\end{document}
のみ使用listings
\documentclass{article}
% --- write to file ---
\usepackage{filecontents}
\begin{filecontents*}{code.txt}
function myfunction(args)
%MYFUNCTION One-line description goes here
% Comments
% about the function
% with an unknown number of lines
[ 2 3 4 ]
command1(); % another comment
command2();
% another comment
command3();
end
\end{filecontents*}
\usepackage{listings}
\makeatletter
% We define a new boolean key for convenience
\lst@Key{onlyheader}{false}[t]{\lstKV@SetIf{#1}\lst@ifonlyheader}
% We'll use this switch to keep track of where we are
\newif\iffirstnoncommentline
% --- Careful! the following modifications are global ---
% (i.e. will apply to all listings)
\lst@AddToHook{PreInit}{\global\firstnoncommentlinetrue}
\lst@AddToHook{Output}{\dropOutput}
\lst@AddToHook{OutputOther}{\dropOutput}
% helper macro
\newcommand\dropOutput
{%
\lst@ifonlyheader%
\ifnum\lst@lineno>1%
\lst@ifLmode%
\else
\iffirstnoncommentline%
\lst@EnterMode\lst@Pmode{}%
\lst@BeginDropOutput\lst@Pmode%
\fi
\global\firstnoncommentlinefalse%
\fi
\fi
\fi
}
\makeatother
\lstset{
language = Matlab,
frame = single,
}
\begin{document}
\lstinputlisting
[caption = {\texttt{onlyheader=false}}]
{code.txt}
\lstinputlisting
[
caption = {\texttt{onlyheader=true}},
onlyheader = true,
]{code.txt}
\lstinputlisting
[
caption = {\texttt{onlyheader=true}},
onlyheader = true,
]{code.txt}
\end{document}
答え2
このようなファイル処理は、必ずしも TeX で一括して処理するのが最適というわけではありません。TeX の外部で処理を行い、その結果を TeX 内で使用する方がはるかに優れています。
このメソッド(LaTeX でシェル出力を変数に保存するにはどうすればよいですか?) は、ある程度妥協した方法です。TeXwrite18
プリミティブを使用してシェル コマンドを実行し、検索する出力を一時ファイルに保存します。この一時ファイルは、リスト ソースとして使用されます。
シェル コマンドの回避策を使用せずに、すべての TeX プリミティブでこれを実行できるかどうか、またその方法についてはまだ検討中です。
\documentclass{article}
\usepackage{listingsutf8}
\begin{document}
% Execute a sed script to identify the lines that are desired
% from the top of your code file (note that the % sign has to be
% escaped in this line, due to LaTeX interpreting it differently)
% This command was developed with sed on Mac OSX 10.9
\immediate\write18{sed -ne '1 h; 2,/^[^\%]/ {x;p;}' myfunction.txt > '\jobname.temp'}
% Sed command:
% 1 h; Take first line, hold in buffer
% 2,/^[^%]/ Lines 2 through the next line that doesn't
% begin with a %
% ... {x;p;} Hold current line in buffer (swap with previous)
% and then print out previously held line
% This results in line 1 + next continuous lines beginning with % printed
% Set language -- looked like MATLAB was a prime candidate given the syntax
\lstset{language=Matlab}
% Print out original function
Contents of \verb!myfunction.txt!:
\lstinputlisting{myfunction.txt}
% Print out newly created file
Dynamic header of \verb!myfunction.txt!:
\lstinputlisting{\jobname.temp}
% Clean up temporary file
\immediate\write18{rm -f -- '\jobname.temp'}
\end{document}
結果は
答え3
パッケージfilecontents
は、入力するファイルを作成するためにのみ使用されます。
コードは要求された行を取得します。それらは直接操作することも、listings
パッケージを使用して操作することもできます。このために、私は再び行をファイルに書き込んで入力します。もっと簡単でエレガントな方法があるはずですが、私はまったく馴染みがないようですlistings
。[更新により が追加されました\lstset{language=Matlab}
]
このアプローチでは、シェル エスケープや外部ツールは不要であることに注意してください。マクロは\GetHeaderAndDisplayWithListing
1 回で作業を実行します。リスト自体は を介してカスタマイズできると思います\lstset
が、私はまだマニュアルの 3 ページ目までしか到達していません。
\documentclass{article}
\usepackage{listings}
\usepackage{filecontents}% only to create files for this example
\begin{filecontents*}{badboysamplefile.txt}
function myfunction(args)
% Comments
% about the function
% with an unknown number of lines
command1(); % another comment
command2();
% another comment
command3();
end
\end{filecontents*}
\begin{filecontents*}{badboyotherfile.txt}
function myfunction(args)
% 1 Comments
% 2 about the function
% 3 with an unknown number of lines
% 4 Comments
% 5 about the function
% 6 with an unknown number of lines
% 7 comments
% 1 Comments
% 2 about the function
% 3 with an unknown number of lines
% 4 Comments
% 5 about the function
% 6 with an unknown number of lines
% 7 comments
command1(); % another comment
command2();
% another comment
command3();
end
\end{filecontents*}
\makeatletter
\def\ExtractLines #1{%
\newread\badboy
\openin\badboy #1\relax
\edef\ELrestore{\endlinechar\the\endlinechar\relax\catcode`\%=14 }%
\endlinechar -1
\ExtractLines@
\ELrestore
%\show\ELrestore
}%
\def\ExtractLines@ {%
\ifeof\badboy
\def\ExtractedLines{}\closein\badboy
\else
\read\badboy to \ExtractedLines
\edef\ExtractedLines{\detokenize\expandafter{\ExtractedLines}}%
\catcode`\% 12
\ExtractLines@@
\fi
}
\def\ELSEP{\par}
\def\ELgetfirst #1#2\ELgetfirst {\def\ELFirst{#1}}
\catcode`\% 12
\catcode`! 14
\def\ExtractLines@@ {!
\ifeof\badboy \closein\badboy\else
\read\badboy to \Extract@OneLine
\edef\Extract@@OneLine{\detokenize\expandafter{\Extract@OneLine}}!
\expandafter\ELgetfirst\Extract@@OneLine.\ELgetfirst
\if %\ELFirst
\expandafter\expandafter\expandafter
\def\expandafter\expandafter\expandafter
\ExtractedLines\expandafter\expandafter\expandafter
{\expandafter\ExtractedLines\expandafter\ELSEP\Extract@@OneLine}!
\expandafter\expandafter\expandafter
\ExtractLines@@
\else
\closein\badboy
\fi
\fi
}
\catcode`% 14
\catcode`\! 12
\makeatother
\newcommand\GetHeaderAndDisplayWithListing [1]{%
\def\ELSEP {^^J}%
\ExtractLines {#1}%
\newwrite\badboy
\immediate\openout\badboy badboy-extracted.temp\relax
\immediate\write\badboy {\ExtractedLines}%
\immediate\closeout\badboy\relax
\lstinputlisting {badboy-extracted.temp}%
\def\ELSEP {\par}% just in case one wants to use \ExtractLines
% and the produced \ExtractedLines directly
}
\begin{document}
% added in update:
\lstset{language=Matlab}
First file with \verb|listings|:\medskip
\GetHeaderAndDisplayWithListing {badboysamplefile.txt}
% \ExtractLines {badboysamplefile.txt}%
% \texttt{\ExtractedLines}
% \bigskip
And the second file with \verb|listings|:\medskip
% \ExtractLines {badboyotherfile.txt}%
% \texttt{\ExtractedLines}
\GetHeaderAndDisplayWithListing {badboyotherfile.txt}
\end{document}
出力(現在は を使用\lstset{language=Matlab}
):
listings
コメントアウトされた および を使用した、\ExtractLines
最初の回答の出力 (パッケージ も必要ありませんでした) \texttt{\ExtractedLines}
: