我想按照以下模式替换文件中的字符串:
<<key q>>
→<kbd>q</kbd>
<<key Ctrl q>>
→<kbd>Ctrl</kbd>+<kbd>q</kbd>
<<key Ctrl Shift Alt q>>
→<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>q</kbd>
更新:该文件还包含其他文本。例子: Press <<key Ctrl q>> to quit.
我能找到的解决此问题的最佳解决方案是sed
使用 1、2、3 和 4 个键的单独脚本进行调用:
sed -i -E \
-e 's|<<key ([^ ]+)>>|<kbd>\1</kbd>|g'
-e 's|<<key ([^ ]+) ([^ ]+)>>|<kbd>\1</kbd>+<kbd>\2</kbd>|g' \
-e 's|<<key ([^ ]+) ([^ ]+) ([^ ]+)>>|<kbd>\1</kbd>+<kbd>\2</kbd>+<kbd>\3</kbd>|g' \
-e 's|<<key ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)>>|<kbd>\1</kbd>+<kbd>\2</kbd>+<kbd>\3</kbd>+<kbd>\4</kbd>|g' \
file.txt
显然,这对于包含 5 个或更多键的宏会失败。
是否有更通用的解决方案适用于n钥匙?不限于sed
.我还尝试使用结构正则表达式(sregx)但找不到如何做。
答案1
我会使用 Perl 来完成这样的任务。
#!/bin/perl
while(<>) {
if (/<<key (.*?)>>/) {
my $pattern_with_keys = $1;
my @keys = split / /, $pattern_with_keys ;
my @kbd_keys = map {"<kbd>$_</kbd>"} @keys;
print join('+', @kbd_keys), "\n";
}
}
运行它perl script.pl < source_file.txt
并享受它。
答案2
- 一次更换一个。
- 重复此操作,直到没有新的更换完成。
- 清除垃圾。
像这样:
sed -E ':start s|(<<key[^>]*) ([^>]*)>>|\1>>+<kbd>\2</kbd>|g; t start; s|<<key>>\+||g'
在哪里:
:start
是一个标签。s|(<<key[^>]*) ([^>]*)>>|\1>>+<kbd>\2</kbd>|g
变成。<<key Ctrl Shift Alt q>>
<<key Ctrl Shift Alt>>+<kbd>q</kbd>
t start
跳转到标签当且s
仅当刚刚替换了任何内容,所以......- …
<<key Ctrl Shift Alt>>+<kbd>q</kbd>
变成
<<key Ctrl Shift>>+<kbd>Alt</kbd>+<kbd>q</kbd>
,然后
<<key Ctrl>>+<kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>q</kbd>
,最后
<<key>>+<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>q</kbd>
。在下一次迭代中s
不替换任何内容(<<key>>
不匹配,因为其中没有空间),因此t
是无操作。 s|<<key>>\+||g
去除残留物。
注意:([^>]*
与 相对.*
)可防止<<key …>>
同一行中多个片段之间的匹配。