Awk
正則表達式:在不知道有多少的情況下引用所有匹配的組
我想按照這種模式替換文件中的字元串:
<<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),但找不到如何做到這一點。
- 一次更換一個。
- 重複直到沒有完成新的更換。
- 清除垃圾。
像這樣:
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
並享受它。