用 sed 替换会忽略空格
Substituting with sed ignores whitespace
假设我有一个名为 m1.txt
的文件,我想将其内容 (- . ... - / -. --- / .----
) 从摩尔斯解码为文本。这是我写的:
sed -i 's/.- /A/g' m1.txt
sed -i 's/-... /B/g' m1.txt
sed -i 's/-.-. /C/g' m1.txt
以此类推,包括数字,以后:
sed -i 's:/ : :g' m1.txt
cat m1.txt
为了清除分隔斜线并输出消息。
预期的输出是 TEST NO 1
,但是程序输出 D...AE-ED.--A
,忽略任何空格并返回错误消息。我做错了什么?
两件事:
- 您需要转义
.
,因为它将匹配任何字符
- 您需要考虑交互,因为
.
(E) 会匹配单个点,它也会匹配 (N) -.
的末尾,除非您按正确的顺序考虑它们或保留分隔符(在左侧和右侧)。
(1) 很明显可以解决,只需转义.
。
对于(2),我们可以首先将行的开头和结尾映射到空格(这样我们的分隔符在左右两侧一致,然后我们在输出时保留分隔符(以避免交互)。然后,在第二个到最后一行,清理空格。然后,在最后一行中,将斜杠映射到分词空格,这是输出中唯一需要的空格。
我没有为你做整个字母表,只是让你看到这个想法。
这是一个可行的解决方案:
$ cat m1.txt
- . ... - / -. --- / .----
$ cat morse.sed
s/^/ /
s/$/ /
s/ - / T /g
s/ \. / E /g
s/ \.\.\. / S /g
s/ -\.\ / N /g
s/ --- / O /g
s/ \.---- / 1 /g
s/[ ]\+//g
s:/: :g
$ cat m1.txt | sed -f morse.sed
TEST NO 1
注意:这个答案被修改了,因为我一开始没有意识到 (
和 )
不是输入的一部分。另外,@Bach Lien 将锚点映射到第一行中的空格的想法很棒,它使事情变得更清晰,所以我已经采纳了这个想法。
莫尔斯码table(莫尔斯码到字符的映射):
$ cat morse-table.txt
## this is table of char-to-morse-code mapping
## taken from https://en.wikipedia.org/wiki/Morse_code
## dated: 2018 01 23
## characters
A .-
B -...
C -.-.
D -..
E .
F ..-.
G --.
H ....
I ..
J .---
K -.-
L .-..
M --
N -.
O ---
P .--.
Q --.-
R .-.
S ...
T -
U ..-
V ...-
W .--
X -..-
Y -.--
Z --..
## numbers
1 .----
2 ..---
3 ...--
4 ....-
5 .....
6 -....
7 --...
8 ---..
9 ----.
0 -----
## special symbols
## in fact, there is no
## such symbols in traditional morse codes
## this part is fake, just for testing
. .......
\ -------
/ -.-.-.-
? --.--.-
[ .--.--.
] --..--.
将摩尔斯 table 转换为 sed
脚本的程序:
$ cat make-m2t.sh
#!/bin/bash
t=morse-table.txt # morse table
s=m2t # sed script
s1=' # s1 = pre-processing
s:\s+: :g # space-gap to TWO space-chars
s:^: : # add a space at line beginning
s:$: : # add a space at line end
s:/: \n :g # change all slash to " \n "
'
s2=' # s2 = morse-table to sed-script
s:\s+: :g # space-gap to space-char
s:##.*$:: # remove all comments
s:^ *:: # remove all leading spaces
s: *$:: # remove all trailing spaces
/^[^ ] [\.-]+$/!d # ignore all invalid lines
s:\.:\.:g # add back-slash for dot (escape for dot)
s:^\\. :\. : # but not for the char-dot
s:^\ :\\ : # add b-slash for b-slash (escape for b-slash)
s:^\/ :\\/ : # add b-slash for slash (escape for slash)
s:^([^ ]+) +([^ ]+).*$:s/ / /g: # morse-map to sed-subsitution
'
s3=' # s3 = post-processing
s: ::g # remove all spaces
s:\n: :g # convert \n to space
'
# now, make the sed script
echo '#!/usr/bin/sed -Ef' >"$s" # shebang
sed -E 's:\s*#.*$::' <<<"$s1" >>"$s" # remove comments from s1
sed -E "$s2" "$t" >>"$s" # convert morse to chars
sed -E 's:\s*#.*$::' <<<"$s3" >>"$s" # remove comments from s3
sed -i -E '/^\s*$/d' "$s" # remove all blank lines
chmod +x "$s" # make it executable
测试:
$ ./make-m2t.sh
$ echo '- . ... -/-. ---/.----' | ./m2t
TEST NO 1
$ echo '.--.--. .... . .-.. .-.. --- --..--./....... --.--.-' | ./m2t
[HELLO] .?
$ cat m1.txt
- . ... - / -. --- / .----
$ ./m2t m1.txt
TEST NO 1
$ cat m2t
#!/usr/bin/sed -Ef
s:\s+: :g
s:^: :
s:$: :
s:/: \n :g
s/ \.- / A /g
s/ -\.\.\. / B /g
s/ -\.-\. / C /g
s/ -\.\. / D /g
s/ \. / E /g
s/ \.\.-\. / F /g
s/ --\. / G /g
s/ \.\.\.\. / H /g
s/ \.\. / I /g
s/ \.--- / J /g
s/ -\.- / K /g
s/ \.-\.\. / L /g
s/ -- / M /g
s/ -\. / N /g
s/ --- / O /g
s/ \.--\. / P /g
s/ --\.- / Q /g
s/ \.-\. / R /g
s/ \.\.\. / S /g
s/ - / T /g
s/ \.\.- / U /g
s/ \.\.\.- / V /g
s/ \.-- / W /g
s/ -\.\.- / X /g
s/ -\.-- / Y /g
s/ --\.\. / Z /g
s/ \.---- / 1 /g
s/ \.\.--- / 2 /g
s/ \.\.\.-- / 3 /g
s/ \.\.\.\.- / 4 /g
s/ \.\.\.\.\. / 5 /g
s/ -\.\.\.\. / 6 /g
s/ --\.\.\. / 7 /g
s/ ---\.\. / 8 /g
s/ ----\. / 9 /g
s/ ----- / 0 /g
s/ \.\.\.\.\.\.\. / . /g
s/ ------- / \ /g
s/ -\.-\.-\.- / \/ /g
s/ --\.--\.- / ? /g
s/ \.--\.--\. / [ /g
s/ --\.\.--\. / ] /g
s: ::g
s:\n: :g
注:
- 用户只需要定义morse-table.txt,就可以将莫尔斯码映射到字符
- 基于莫尔斯码-table,
bash
程序会生成 sed
脚本以将莫尔斯电码转换为文本
sed
脚本基于@JawguyChooser的解决方案
- 因为我们使用space
' '
作为莫尔斯块的"delimiter",所以,在预处理时我们必须将所有space间隙转换为两个space-人物;否则会出现错误 'HELLO'
(double L
)
假设我有一个名为 m1.txt
的文件,我想将其内容 (- . ... - / -. --- / .----
) 从摩尔斯解码为文本。这是我写的:
sed -i 's/.- /A/g' m1.txt
sed -i 's/-... /B/g' m1.txt
sed -i 's/-.-. /C/g' m1.txt
以此类推,包括数字,以后:
sed -i 's:/ : :g' m1.txt
cat m1.txt
为了清除分隔斜线并输出消息。
预期的输出是 TEST NO 1
,但是程序输出 D...AE-ED.--A
,忽略任何空格并返回错误消息。我做错了什么?
两件事:
- 您需要转义
.
,因为它将匹配任何字符 - 您需要考虑交互,因为
.
(E) 会匹配单个点,它也会匹配 (N)-.
的末尾,除非您按正确的顺序考虑它们或保留分隔符(在左侧和右侧)。
(1) 很明显可以解决,只需转义.
。
对于(2),我们可以首先将行的开头和结尾映射到空格(这样我们的分隔符在左右两侧一致,然后我们在输出时保留分隔符(以避免交互)。然后,在第二个到最后一行,清理空格。然后,在最后一行中,将斜杠映射到分词空格,这是输出中唯一需要的空格。
我没有为你做整个字母表,只是让你看到这个想法。
这是一个可行的解决方案:
$ cat m1.txt
- . ... - / -. --- / .----
$ cat morse.sed
s/^/ /
s/$/ /
s/ - / T /g
s/ \. / E /g
s/ \.\.\. / S /g
s/ -\.\ / N /g
s/ --- / O /g
s/ \.---- / 1 /g
s/[ ]\+//g
s:/: :g
$ cat m1.txt | sed -f morse.sed
TEST NO 1
注意:这个答案被修改了,因为我一开始没有意识到 (
和 )
不是输入的一部分。另外,@Bach Lien 将锚点映射到第一行中的空格的想法很棒,它使事情变得更清晰,所以我已经采纳了这个想法。
莫尔斯码table(莫尔斯码到字符的映射):
$ cat morse-table.txt
## this is table of char-to-morse-code mapping
## taken from https://en.wikipedia.org/wiki/Morse_code
## dated: 2018 01 23
## characters
A .-
B -...
C -.-.
D -..
E .
F ..-.
G --.
H ....
I ..
J .---
K -.-
L .-..
M --
N -.
O ---
P .--.
Q --.-
R .-.
S ...
T -
U ..-
V ...-
W .--
X -..-
Y -.--
Z --..
## numbers
1 .----
2 ..---
3 ...--
4 ....-
5 .....
6 -....
7 --...
8 ---..
9 ----.
0 -----
## special symbols
## in fact, there is no
## such symbols in traditional morse codes
## this part is fake, just for testing
. .......
\ -------
/ -.-.-.-
? --.--.-
[ .--.--.
] --..--.
将摩尔斯 table 转换为 sed
脚本的程序:
$ cat make-m2t.sh
#!/bin/bash
t=morse-table.txt # morse table
s=m2t # sed script
s1=' # s1 = pre-processing
s:\s+: :g # space-gap to TWO space-chars
s:^: : # add a space at line beginning
s:$: : # add a space at line end
s:/: \n :g # change all slash to " \n "
'
s2=' # s2 = morse-table to sed-script
s:\s+: :g # space-gap to space-char
s:##.*$:: # remove all comments
s:^ *:: # remove all leading spaces
s: *$:: # remove all trailing spaces
/^[^ ] [\.-]+$/!d # ignore all invalid lines
s:\.:\.:g # add back-slash for dot (escape for dot)
s:^\\. :\. : # but not for the char-dot
s:^\ :\\ : # add b-slash for b-slash (escape for b-slash)
s:^\/ :\\/ : # add b-slash for slash (escape for slash)
s:^([^ ]+) +([^ ]+).*$:s/ / /g: # morse-map to sed-subsitution
'
s3=' # s3 = post-processing
s: ::g # remove all spaces
s:\n: :g # convert \n to space
'
# now, make the sed script
echo '#!/usr/bin/sed -Ef' >"$s" # shebang
sed -E 's:\s*#.*$::' <<<"$s1" >>"$s" # remove comments from s1
sed -E "$s2" "$t" >>"$s" # convert morse to chars
sed -E 's:\s*#.*$::' <<<"$s3" >>"$s" # remove comments from s3
sed -i -E '/^\s*$/d' "$s" # remove all blank lines
chmod +x "$s" # make it executable
测试:
$ ./make-m2t.sh
$ echo '- . ... -/-. ---/.----' | ./m2t
TEST NO 1
$ echo '.--.--. .... . .-.. .-.. --- --..--./....... --.--.-' | ./m2t
[HELLO] .?
$ cat m1.txt
- . ... - / -. --- / .----
$ ./m2t m1.txt
TEST NO 1
$ cat m2t
#!/usr/bin/sed -Ef
s:\s+: :g
s:^: :
s:$: :
s:/: \n :g
s/ \.- / A /g
s/ -\.\.\. / B /g
s/ -\.-\. / C /g
s/ -\.\. / D /g
s/ \. / E /g
s/ \.\.-\. / F /g
s/ --\. / G /g
s/ \.\.\.\. / H /g
s/ \.\. / I /g
s/ \.--- / J /g
s/ -\.- / K /g
s/ \.-\.\. / L /g
s/ -- / M /g
s/ -\. / N /g
s/ --- / O /g
s/ \.--\. / P /g
s/ --\.- / Q /g
s/ \.-\. / R /g
s/ \.\.\. / S /g
s/ - / T /g
s/ \.\.- / U /g
s/ \.\.\.- / V /g
s/ \.-- / W /g
s/ -\.\.- / X /g
s/ -\.-- / Y /g
s/ --\.\. / Z /g
s/ \.---- / 1 /g
s/ \.\.--- / 2 /g
s/ \.\.\.-- / 3 /g
s/ \.\.\.\.- / 4 /g
s/ \.\.\.\.\. / 5 /g
s/ -\.\.\.\. / 6 /g
s/ --\.\.\. / 7 /g
s/ ---\.\. / 8 /g
s/ ----\. / 9 /g
s/ ----- / 0 /g
s/ \.\.\.\.\.\.\. / . /g
s/ ------- / \ /g
s/ -\.-\.-\.- / \/ /g
s/ --\.--\.- / ? /g
s/ \.--\.--\. / [ /g
s/ --\.\.--\. / ] /g
s: ::g
s:\n: :g
注:
- 用户只需要定义morse-table.txt,就可以将莫尔斯码映射到字符
- 基于莫尔斯码-table,
bash
程序会生成sed
脚本以将莫尔斯电码转换为文本 sed
脚本基于@JawguyChooser的解决方案- 因为我们使用space
' '
作为莫尔斯块的"delimiter",所以,在预处理时我们必须将所有space间隙转换为两个space-人物;否则会出现错误'HELLO'
(doubleL
)