正则表达式:引用所有匹配组而不知道有多少个

正则表达式:引用所有匹配组而不知道有多少个

我想按照以下模式替换文件中的字符串:

  • <<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

  1. 一次更换一个。
  2. 重复此操作,直到没有新的更换完成。
  3. 清除垃圾。

像这样:

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 …>>同一行中多个片段之间的匹配。

相关内容