一个典型的乳胶问题:
\SomeStyle{\otherstyle{this is the \textit{nested part} some more text...}}
现在我想删除所有\SomeStyle{...}
内容但不删除内容。内容包含嵌套括号。上面的行应改为:
\otherstyle{this is the \textit{nested part} some more text...}
问题:
- 是否有任何 Latex 编辑器可以提供此方法?
- 什么编辑器/脚本可以做到这一点?
- 如何用 sed 来实现?[🤓]
我的解决方案是使用 sed 的 bash 脚本。
- 准备文本:用 ascii 铃声标记替换字符串,在每个括号后添加换行符
- 循环:查找 { -> 将 X 添加到保持空间,查找 } -> 从保持空间中移除 X,保持空间为空 -> 移除关闭 }
- 恢复换行符和 ascii 铃声到以前的
脚本可以运行但会失败:
\badstyle{w}\badstyle{o}\badstyle{r}\badstyle{d}
它将变成:
wo}rd}
分支到 :f 似乎不起作用。
F=$(sed 's|\\|\\\\|g;s|{|\\{|g' <<< "$1" )
# mark all removestrings with ascii bell and newline
# add newline after each { and }
SEDpre='
s|'"$F"'|\a%\n|g
s|\{|\{\n|g
s|\}|\}\n|g
'
SEDpost='
:a;N;$!ba;
s|\a%\n||g
s|\{\n|\{|g
s|\}\n|\}|g
'
# count the brackets
SED='
/\a%/{
:a
n
:f
/\{/{x;s|$|X|;x;ba}
/\}/{x;
s|X||;
/^$/{x;bb}
x
ba
}
}
b
:b
/\}/{
s|\}||;
N;
s|\n||;
/\a%/bf
}
'
sed -r -E "$SEDpre" "$2" | sed -rE "$SED" | sed -rE "$SEDpost"
典型的方法是使用
perl
递归正则表达式功能:或者如果你必须考虑括号转义为
\{
(并\
转义为\\
)¹其中,我们
[^{}]*
用替换(?:\\.|[^{}\\])*
来匹配\anycharacter
(包括\\
、\{
和\}
我们在这里关心的)以及\
、{
、 和之外的字符}
。(?:...)
是 的非捕获形式(...)
。(添加
-i
编辑文件i
n-place 的选项)。上面
(?1)
就像在第一对中插入正则表达式(...)
,所以(\{((?:(?1)|\\.|[^\\{}])*+)\})
在那一点上。如果
\SomeStyle{...}
s 可以嵌套,如下所示:更改为:
然后将其改为:
这将重复该过程,先替换外部的,直到找到不匹配的。
对任意样式和文件执行此操作:
假设
sed
整个输入可以适合模式空间的实现,一种方法(也处理嵌套的,在这种情况下从内部的开始)可能是:(与在命令行中删除(可能嵌套的)文本引号以及此处的其他一些方法相同)。
一些
sed
实现已复制了 perl-i
以进行就地编辑,但请注意,在某些情况下(FreeBSD 及其衍生产品),您需要-i ''
进行就地编辑而无需备份原始文件。-i.back
将在具有-i
(和 perl 中)的所有实现中工作并将原始文件保存为file.tex.back
。您
sed
似乎是 GNU,sed
因为您使用了相当多的 GNUisms,并且 GNUsed
确实支持-i
à laperl
,并且据我所知,除了可用内存之外,模式空间的大小没有限制。为了解释转义为
\{
(和\
转义为\\
)¹的括号,您可以使用现在的标准-E
选项(最好是 GNU 特定的-r
)切换到具有|
交替运算符的扩展正则表达式,但请注意,{
然后也会成为正则表达式运算符,并且需要在外面时进行转义[...]
,并且分组+捕获从更改\(...\)
为(...)
:¹ 仍然忽略可能存在的可能性
\\SomeStyle{something}
,不处理注释或\verb|...|
...覆盖这些并进行完整的 TeX 标记化是可能的,但可能不值得付出努力,具体取决于您的实际输入。使用Raku(以前称为 Perl_6)
使用 Raku 的递归正则表达式符号匹配您想要的目标
<~~>
:示例输入:
示例输出:
Raku 提供了一种新的 Regex 语法,有些人认为它更容易阅读。代码几乎逐字逐句地摘自 Raku 的Regex 文档页面。在这里,我们只需使用 Raku 的
m///
match 运算符,并使用:g
命名参数将其设为全局:\{ ~ \} <expression>
表示嵌套结构的波浪符号语法,<-[{}]>*
自定义负字符类,包含除{}
花括号之外的任何字符。ICYMI,<+[{}]>*
或者更简单地<[{}]>*
表示正字符类,<~~>
递归正则表达式,<(
在 Raku 中, …表示捕获标记)>
。要处理文件以纠正有问题的行并逐字输出无问题的行,请使用 Raku 的三元运算符:测试
??
True!!
False。不幸的是,目前上述所有代码示例都只是
Style
以逐行方式删除了顶层(以及相关括号),无论它Style
是什么。我会努力纠正这种缺乏特异性的问题。敏锐的观察者可能会注意到,上述所有答案都使用了 Raku 的
m///
匹配运算符。仅供参考,我确信有一种方法可以使用 Raku 的替换运算符(与 Raku 的...捕获标记s///
结合使用)来实现这一点,但我想先发布这些匹配答案。<(
)>
m///
这是一个可能的
sed
机制。为简单起见,我们假设没有下划线字符,因此我们可以使用一个下划线字符作为标记。这就像您的 ASCII 铃铛。我们将标记插入行首,然后逐个字符地移动它,直到行尾。每次移动时,我们都会在行首{
添加一个符号作为计数器。每次移动时,我们都从开头删除一个。如果我们没有更多符号,那么我们就平衡了括号,并且可以应用所需的替换,直到标记。+
}
+
+
如果该行以
+
already 开头,我们先在!!
开头添加,然后在结尾删除它。使用任何 awk:
上面的代码并没有尝试处理输入中的转义
{
或}
,因为它需要将\{
(转义{
)与\\{
(转义\
后跟{
)区别对待,而这需要比我愿意投入的更多的思考,因为它没有出现在示例输入中,所以可能实际上不是OP的问题,如果是的话,他们总是可以问一个后续问题,而他们还没有办法处理它。更新:在与@StéphaneChazelas在他的答案下的评论中进行讨论后,我相信您只需要在用于处理转义的或输入的正则表达式中替换
[^{}]
为。(\\.|[^{}\\])
match()
{
}
它假定每个
\SomeStyle{
或 确实{
有一个匹配的}
。这是上述内容的注释版本,因为乍一看可能不太清楚它在做什么:
该脚本检查替换字符串输入是否正确(无括号),检查目标文件中的转义括号({,})并创建备份。
sed 方法/perl 方法: