Yim*_*ong 2 sed awk text-processing regular-expression
例如,根据维基词典,这是“when”的发音。enPR、IPA 和 X-SAMPA 是不同的发音方案。
when:* {{a|US}} {{enPR|w?n|hw?n}}, {{IPA|/w?n/|/??n/}}, {{X-SAMPA|/wEn/|/WEn/}}
Run Code Online (Sandbox Code Playgroud)
我想提取关键字when
及其两个 IPA 发音,并将它们放在单独的行中:
when w?n
when ??n
Run Code Online (Sandbox Code Playgroud)
一个词可能有一个、两个或多个 IPA 发音,可能有也可能没有 enPR 或 X-SAMPA 发音。
我在考虑 PHP,列表中的列表,但这似乎有点矫枉过正,如果可能的话,我不希望用户必须安装它。有没有办法在 awk、sed、cut 或其他标准的 Unix 命令行实用程序中做到这一点?
使用sed
,您可以将其写为:
sed '/\([^:]*\):.*{IPA|\([^}]*\).*/!d;s//\1 \2/;s,/,,g;:1
s/\(\([^ ]*\).*\)|/\1\n\2 /;t1'
Run Code Online (Sandbox Code Playgroud)
上面的命令可以分解如下:
解析输入when: ... {IPA|...}
并删除不匹配的行。
在 /pattern/!d; s//repl/
我们 [d] 丢弃不[!] 匹配模式的行,然后在下一个 [s] 替换命令中重用相同的模式(空模式意味着重用最后一个模式)。与其 [d] 删除不匹配的行,我们可以通过使用b
代替使它们保持不变d
,或者如果我们知道所有行都匹配模式,我们可以s/pattern/repl/
直接使用。
/\([^:]*\):.*{IPA|\([^}]*\).*/
Run Code Online (Sandbox Code Playgroud)
该模式将数据分成 2 个块。第一个块是when:
. 这段代码\([^:]*\):
说要获取所有字符,直到遇到 a:
并将其保存在临时文件中。变量 ( \1
)
:
到 和之间的所有字符{IPA|
都将被跳过。保存的下一个位是IPA|
. 这是由这个代码块完成的,\([^}]*\)
,它说保存所有代码,直到}
遇到 a 。这保存在变量 ( \2
) 中。
注意:在sed
任何时候你想保存一段字符串,你可以把它用括号括起来。他们需要用 a 进行转义,\
以便sed
知道您不是指字面意义上的括号。像这样:\( savethis \)
。
$ sed 's/\([^:]*\):.*{IPA|\([^}]*\).*/\1 \2/;' sample.txt
when /w?n/|/??n/
Run Code Online (Sandbox Code Playgroud)删除所有正斜杠 ( /
)
这个看起来更复杂,因为它使用了备用分隔符。您通常会使用 form s///g
,但sed
让您即时组成分隔符,因此我们使用逗号 ( s,,,g
)代替。此块搜索/
并用空替换它们。
$ sed '/\([^:]*\):.*{IPA|\([^}]*\).*/!d;s//\1 \2/;s,/,,g;' sample.txt
when w?n|??n
Run Code Online (Sandbox Code Playgroud)遍历每个 IPA
:1 s/\(\([^ ]*\).*\)|/\1\n\2 /;t1
Run Code Online (Sandbox Code Playgroud)
这是迄今为止该解决方案中最复杂的部分。很难看出发生了什么,但这个块是一个条件分支。
:label command(s) t label
Run Code Online (Sandbox Code Playgroud)
标签是:1
命令s/\(\([^ ]*\).*\)|/\1\n\2 /;
,t label
是查看前一个命令是否修改了模式空间的“测试”。如果是,则跳转到 label 1
,因此t1
.
循环内的命令
如果我们label ... loop
拿出一秒钟,并增加我们的 IPA 示例使其具有 3,您可以更好地看到正在发生的事情。
{{IPA|/w?n/|/??n/|/blah/}}
Run Code Online (Sandbox Code Playgroud)
到此为止,我们将使用前面的命令结束此操作。
when w?n|??n|blah
Run Code Online (Sandbox Code Playgroud)
如果我们现在运行这个:
$ echo "when w?n|??n|blah" | sed 's/\(\([^ ]*\).*\)|/\1 \2 /;'
Run Code Online (Sandbox Code Playgroud)
我们得到这个:
when w?n|??n
when blah
Run Code Online (Sandbox Code Playgroud)
你能看到它现在在做什么吗?是的,我也没有,所以让我们稍微简化一下,去掉换行符 ( \n
) 并换入一些较短的字符串。
$ echo "X C1|C2|C3" | sed 's/\(\([^ ]*\).*\)|/\1 \2 /;'
X C1|C2 X C3
Run Code Online (Sandbox Code Playgroud)
现在这里发生的事情是代码\(\([^ ]*\).*\)|
很聪明,因为它嵌套了括号,因此它们就像这样( ( ) )
。在内部括号中匹配的是任何不是空格的东西。这是when
字符串。外括号匹配直到最后一个管道 ( |
) 的所有内容。
这个代码片段的另一个有趣的事情是对括号进行排序,以便外部的存储在里面,\1
而内部的存储在\2
. 这是因为sed
根据遇到它们的顺序对它们进行编号。
您可以通过使用附加的\1
's 和\2
's扩展代码段来说服自己。
$ echo "X C1|C2|C3" | sed 's/\(\([^ ]*\).*\)|/\1 \1 \1 /;'
X C1|C2 X C1|C2 X C1|C2 C3
$ echo "X C1|C2|C3" | sed 's/\(\([^ ]*\).*\)|/\1 \2 \2 /;'
X C1|C2 X X C
Run Code Online (Sandbox Code Playgroud)
所以循环内的命令基本上是取了X
2次。一次作为整体的一部分X C1|C2
(外括号),第二次作为空间的任何内容(内括号)。
回到条件分支
好的,所以分支基本上会调用 #5 中的命令,对于 IPA 的数量超过 2.sed
的分支构造将继续重新运行命令,直到命令不再修改替换,此时它停止。
$ echo "X C1|C2|C3" | sed ':1 s/\(\([^ ]*\).*\)|/\1\n\2 /; t1'
X C1
X C2
X C3
Run Code Online (Sandbox Code Playgroud)希望以上内容能帮助其他路人在未来得到这个答案。
归档时间: |
|
查看次数: |
159 次 |
最近记录: |