用sed代替忽略空格

时间:2018-01-22 16:45:19

标签: bash sed morse-code

我们假设我有一个名为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,忽略任何空格并返回错误信息。我做错了什么?

2 个答案:

答案 0 :(得分:4)

两件事:

  1. 您需要转义.,因为它会匹配任何字符
  2. 您需要考虑互动,因为.(E)将匹配单个点,它也会匹配(N)-.的结尾,除非您按正确的顺序考虑它们或保留分隔符(左右两侧)。
  3. (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想要将锚点映射到第一行中的空格是一个很好的想法,它使事情变得更加清晰,所以我已经将这个想法融入其中。

答案 1 :(得分:3)

莫尔斯表(莫尔斯到字母映射):

$ 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
. .......
\ -------
/ -.-.-.-
? --.--.-
[ .--.--.
] --..--.

将莫尔斯桌转换为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/ \2 / \1 /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

注意:

  1. 用户只需要定义morse-table.txt,将莫尔斯代码映射到字符
  2. 基于莫尔斯表,bash程序会生成sed脚本以将莫尔斯代码转换为文本
  3. sed脚本基于@JawguyChooser的解决方案。
  4. 因为我们使用空格' '作为&#34;分隔符&#34;莫尔斯块,所以,当预处理我们必须将所有空间间隔转换为两个空格字符;否则会出现'HELLO'(双L
  5. 等字词的错误