Awk

正則表達式:在不知道有多少的情況下引用所有匹配的組

  • August 23, 2022

我想按照這種模式替換文件中的字元串:

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

對於這個問題,我能找到的最佳解決方案是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. 一次更換一個。
  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 …>>

我會和 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並享受它。

引用自:https://unix.stackexchange.com/questions/714585