如果我有一个包含以下内容的 LaTeX3 字符串:
def f():
return 42
def g():
return 43
我想把它变成:
def f():
return 42
def g():
return 43
即,删除最大数量的前导空格/制表符(忘记仅包含空格/制表符的空行,我将制表符和空格计为同一单位)以确保我在每一行删除了相同数量的空格而不删除实际文本。
什么是最有效的解决方案?(理想情况下是在 LaTeX3 中)我正在考虑使用正则表达式^[ \t]$
来检查行是否仅包含空格,然后使用另一个正则表达式来计算每行前导空格的数量^[ \t]
,但正则表达式在 LaTeX 中效率低下,因此它不是一个真正可行的解决方案。
平均能量损失
\documentclass[]{article}
\usepackage{verbatim}
\usepackage{xsimverb}
\begin{document}
\ExplSyntaxOn
\ior_new:N \g__robExt_read_ior%
\NewDocumentEnvironment{getString}{}{%
\XSIMfilewritestart*{\jobname-tmp-file-you-can-remove.tmp}%
}{%
\XSIMfilewritestop%
\ior_open:Nn \g__robExt_read_ior {\jobname-tmp-file-you-can-remove.tmp}%
%% Put the file in l__robExt_tmp_contain_file_str
\str_clear_new:N \l__robExt_tmp_str%
\ior_str_map_inline:Nn \g__robExt_read_ior {%
\str_gput_right:Nx \l__robExt_tmp_str {##1^^J}%
}%
\str_gset_eq:cN {l__my_string_str} \l__robExt_tmp_str%
}%
\NewDocumentCommand{\printVerbatimString}{}{%
% For some reasons, newlines are displayed as \Omega. We need to replace them with \\
% https://tex.stackexchange.com/questions/694716/print-latex3-string-verbatim/694717
\tl_set_eq:NN \l__robExt_tmp_tl \l__my_string_str
\tl_replace_all:Nnn \l__robExt_tmp_tl {^^J} { \mbox{}\par }%mbox needed to print empty lines
\tl_replace_all:Nnn \l__robExt_tmp_cl { ~ } { \ }
\begin{flushleft}\ttfamily%
\l__robExt_tmp_tl
\end{flushleft}%
}
\ExplSyntaxOff
\begin{getString}
def f():
return 42
def g():
return 43
\end{getString}
\noindent Before:
\printVerbatimString
Goal:
\begin{getString}
def f():
return 42
def g():
return 43
\end{getString}
\printVerbatimString
\end{document}
答案1
下面的操作可以满足您的要求。这可能不是最快的方法,但应该相当简单。
我通过计算删除所有前导符号之前和之后字符串中的空格数来计算要删除的前导符号数。空格删除器只是循环计算前导空格的最小数量,每次删除一个空格或制表符。
\documentclass[]{article}
\usepackage{verbatim}
\usepackage{xsimverb}
\ExplSyntaxOn
\ior_new:N \g__robExt_read_ior
\tl_new:N \l__robExt_tmp_tl
\str_new:N \l__robExt_tmp_str
\int_new:N \l__robExt_whitespaces_int
\seq_new:N \l__robExt_lines_seq
\str_new:N \g__my_string_str
\group_begin:
\char_set_catcode_other:N \^^I
\cs_new_protected:Npn \__robExt_count_leading_whitespace:n #1
{
\str_set:Nn \l__robExt_tmp_str {#1}
\str_replace_all:Nnn \l__robExt_tmp_str { ^^I } { ~ }
\tl_if_blank:VF \l__robExt_tmp_str
{
\int_set:Nn \l__robExt_whitespaces_int
{
\int_min:nn
{ \l__robExt_whitespaces_int }
{
\str_count_spaces:N \l__robExt_tmp_str -
\str_count_spaces:e
{ \exp_last_unbraced:NV \use:n \l__robExt_tmp_str {} }
}
}
}
}
\cs_generate_variant:Nn \str_count_spaces:n { e }
\cs_new:Npn \__robExt_whitespace_trimmer:n #1
{
\use:e
{
\exp_not:n { \__robExt_whitespace_trimmer:nN {#1} }
\prg_replicate:nn
{ \l__robExt_whitespaces_int - 1 }
{ \exp_not:N \__robExt_whitespace_trimmer:nN }
}
\use:n
\prg_break_point:
}
\cs_new:Npn \__robExt_whitespace_trimmer:nN #1#2
{
\tl_if_empty:nT {#1} \prg_break:
\tl_if_head_is_space:nTF {#1}
{ \exp_args:No #2 { \__robExt_whitespace_trimmer:w #1 } }
{
\tl_if_head_eq_charcode:nNTF {#1} ^^I
{ \exp_args:No #2 { \use_none:n #1 } }
{ \prg_break:n {#1} }
}
}
\exp_last_unbraced:NNo \cs_new:Npn \__robExt_whitespace_trimmer:w \c_space_tl {}
\group_end:
\NewDocumentEnvironment { getString } {}
{ \XSIMfilewritestart*{\jobname-tmp-file-you-can-remove.tmp} }
{
\XSIMfilewritestop
\ior_open:Nn \g__robExt_read_ior { \jobname-tmp-file-you-can-remove.tmp }
%% Put the file in l__robExt_tmp_contain_file_str
\seq_clear:N \l__robExt_lines_seq
\int_set_eq:NN \l__robExt_whitespaces_int \c_max_int
\ior_str_map_inline:Nn \g__robExt_read_ior
{
\__robExt_count_leading_whitespace:n {##1}
\seq_put_right:Nn \l__robExt_lines_seq {##1}
}
\int_compare:nNnT \l__robExt_whitespaces_int > \c_zero_int
{
\seq_set_map_e:NNn \l__robExt_lines_seq \l__robExt_lines_seq
{ \__robExt_whitespace_trimmer:n {##1} }
}
\str_gset:Nx \g__my_string_str { \seq_use:Nn \l__robExt_lines_seq { ^^J } }
}
\NewDocumentCommand \printVerbatimString {}
{
% For some reasons, newlines are displayed as \Omega. We need to replace them with \\
% https://tex.stackexchange.com/questions/694716/print-latex3-string-verbatim/694717
\tl_set_eq:NN \l__robExt_tmp_tl \g__my_string_str
\tl_replace_all:Nnn \l__robExt_tmp_tl {^^J} { \mbox{}\par }%mbox needed to print empty lines
\tl_replace_all:Nnn \l__robExt_tmp_tl { ~ } { \ }
\begin{flushleft}\ttfamily
\l__robExt_tmp_tl
\end{flushleft}
}
\ExplSyntaxOff
\begin{document}
\begin{getString}
def f():
return 42
def g():
return 43
\end{getString}
\noindent Before:
\printVerbatimString
Goal:
\begin{getString}
def f():
return 42
def g():
return 43
\end{getString}
\printVerbatimString
\end{document}
答案2
您可以使用autogobble
选项来minted
实现这一点。但是minted
需要--shell-escape
。
\documentclass{article}
\usepackage{minted}
\begin{document}
\begin{minted}{python}
def f():
return 42
def g():
return 43
\end{minted}
\bigskip
\begin{minted}[autogobble]{python}
def f():
return 42
def g():
return 43
\end{minted}
\end{document}