如何从文本中删除特定的乳胶命令并在其后面添加右括号,但将文本保留在括号内?以下示例中要删除的命令是\edit{<some staff>}
。\edit{
和}
应该被删除,而<some staff>
应该保持不变。
请随意填写建议 SED、AWK、Perl 或任何可以完成这项工作的内容
无意义的例子:
We \edit{Introduce a} model for analyzing \emph{data} from various
experimental designs, \edit{such as paired or \url{http://www/}
longitudinal; as was done 1984 by NN \cite{mycitation} and by NNN
\cite{mycitation2}}.
\command{smth}
请注意,语句内的表单中可能存在一个或多个 Latex 命令\edit{}
。\command{smth}
应该保持原样
输出:
We Introduce a model for analyzing \emph{data} from various
experimental designs, such as paired or \url{http://www/}
longitudinal; as was done 1984 by NN \cite{mycitation} and by NNN
\cite{mycitation2}.
附言。我将对我的文本文件进行许多小的编辑。我希望突出显示这些编辑,以便我的合作者可以看到它们。但之后,我想删除所有突出显示并将文本发送给审阅者。
这个问题最初是在AWK/SED 从文本中删除特定的 Latex 命令并在其后面添加右括号。但例如太软了
答案1
\edit{...}
下面是一个在最多只有一层命令的简单情况下工作的命令:
perl -00 -lpe 's,\\edit\{( (?: [^}\\]* | \\[a-z]+\{[^}]*\} )+ )\},$1,xg'
中间部分(?: [^}\\]* | \\[a-z]+\{[^}]*\} )+
有替代方案:
[^}\\]*
匹配任何没有右大括号或反斜杠的字符串(常规文本);并\\[a-z]+\{[^}]*\}
用反斜杠、小写字母和一对匹配的大括号(例如\url{whatever...}
)匹配任何内容。分组(?:...)+
会重复这些替代项以及外部括号捕获,因此我们可以仅用内部的部分替换匹配项\edit{...}
。
-00
告诉 Perl 一次处理一个段落的输入,并用空行分隔段落。如果您需要处理跨段落的标签,请将其更改为-0777
一次性处理整个输入(-0
对于 NUL 分隔的输入也适用,因为文本文件不会有任何输入)。
对于您的示例,这似乎有效,给出:
We Introduce a model for analyzing \emph{data} from various
experimental designs, such as paired or \url{http://www/}
longitudinal; as was done 1984 by NN \cite{mycitation} and by NNN
\cite{mycitation2}.
然而,它(可以预见)对于包含两级命令的输入会失败\edit{...}
:
Some \edit{\somecmd{\emph{nested} commands} here}.
转到:
Some \somecmd{\emph{nested} commands here}.
(删除了错误的右大括号)
实际上处理平衡括号有点棘手,例如在这个问题中对此进行了讨论: Perl正则表达式:匹配嵌套括号。
答案2
我有一个基于Python的解决方案,不够简洁,但使用嵌套命令表现良好。
def command_remove(tex_in, keywords):
# Romove command with curly bracket
# keywords: "hl textbf" mean removing \hl{} and \textbf{}
pattern = '\\\\(' + keywords.replace(' ', '|') + '){'
commands = re.finditer(pattern, tex_in)
idxs_to_del = [] # The index of }
for command in commands:
stack = 0
current_loc = command.span()[1]
while not (tex_in[current_loc] == '}' and stack == 0):
if tex_in[current_loc] == '}':
stack = stack - 1
if tex_in[current_loc] == '{':
stack = stack + 1
current_loc = current_loc + 1
idxs_to_del.append(current_loc)
idxs_to_del = sorted(idxs_to_del, reverse=True) # sort
tex_list = list(tex_in)
for idx in idxs_to_del:
tex_list.pop(idx) # remove }
tex_out = ''.join(tex_list)
tex_out = re.sub(pattern, '', tex_out) # remove \xxx{
return tex_out
它通过正则表达式定位目标命令,然后通过堆栈定位右括号的位置。对于:tex_out = command_remove(tex_in, "revise textbf")
tex_in
\hl{Can you} \revise{can a \textbf{can} as a \emph{canner} can} can a can?
我们会得到tex_out
:
\hl{Can you} can a can as a \emph{canner} can can a can?
更多详细信息,即命令行运行,位于Latex_命令_删除。
答案3
要\edit{...}
使用 LaTeX 命令(意味着其他{...}
对)处理 s,您可以使用perl
的能力在其正则表达式中处理递归:
perl -pe 's{\\edit(\{((?:[^{}]++|(?1))*)\})}{$2}g' file
其中(?1)
回忆了第一对中的正则表达式(...)
,这里是匹配一对的正则表达式{...}
。
(这里不处理转义的大括号或\verb
注释,并假设\edit{...}
s 不跨越多行,如果需要,所有这些都可以相当容易地添加)。