acokikoy's notes

{"勉強中":"Python","注目":"Shopify","LOVE♡":["ABARTH595","TA-GG9","Ukulele","Movable Type","ガーナ ミルクチョコレート"]} なWebディレクター

毎朝Codewars@2019.05.07(火): Decode the Morse Code, advanced

毎朝ちびちびCodewars。

Decode the Morse Code, advanced [4級] https://www.codewars.com/kata/decode-the-morse-code-advanced/

www.codewars.com

今日のお題:

""" モールス信号デコーダー2 - ビットレートが異なるデジタル信号からのデコード

新たに書く関数decodeBits(bits) で デジタル信号を'.(ドット)'と '-(ハイフン)' からなる
モールス信号までデコードする。それを、
(前回のチャレンジ)[https://acokikoy.hatenablog.com/entry/2019/05/05/223341]で書いた
decodeMorse(morseCode)関数に受け渡し、人が理解できるメッセージ文へとデコードする。

decodeBits(bits): 
Args:
    bits (str): デジタル信号
            - "Dot" – 1 unit時間分の'1'
            - "Dash" – 3 unit時間分の'1'
            - ビット間の区切り - 1 unit時間分の'0'
            - 文字間の区切り -  3 unit時間分の'0'
            - 単語間の区切り - 7 unit時間分の'0'

Returns:
     '.(ドット)'と '-(ハイフン)' ’ (スペース)' からなるモールス信号(str)
"""

コード

me

# Decode the Morse Code, advanced [4級]
# https://www.codewars.com/kata/decode-the-morse-code-advanced/

def decodeBits(bits):
    # ToDo: Accept 0's and 1's, return dots, dashes and spaces
    bits = bits.strip('0')
    unit = len(sorted(set(bits.split('1') + bits.split('0')) - {''}, key = len)[0])
    return bits.replace('111'*unit, '-').replace('1'*unit, '.').replace('0000000'*unit, '   ').replace('000'*unit, ' ').replace('0'*unit, '') 

def decodeMorse(morseCode):
    # ToDo: Accept dots, dashes and spaces, return human-readable message
    morse_list = morseCode.strip().replace('   ', ' # ').split()
    message = ''

    for m in morse_list:
        if m == '#':
            message += ' '
        else:
            message += MORSE_CODE[m]
    return message
  • ビットレートは毎回異なるので、これを求めるところがポイント。
  • 信号1単位分の長さをunitとすると、 unit = 連続する'0' ないし'1'の、最短長
  • ビットレート(unit)がわかれば、あとはbitsを長いパターンから順に変換することでモールス信号が求まる。

      '111' * unit  =>  '-'
      '1' * unit     =>  '.'
    
      '0000000' * unit   =>  wordの区切り'   '
      '000'          * unit  =>  letterの区切り' '
      '0'              * unit  =>  信号の区切り(削除)
    
  • 最初書いた流れでsetを使っているが、sorted(key=len)で文字長比較するなら、わざわざsetを使って要素を減らす必要はなかったかも。

文法、関数・メソッドnote

sorted(iterable, *, key=None, reverse=False)
https://docs.python.org/ja/3/library/functions.html#sorted

  • iterable の要素を並べ替えた新たなリストを返す。
  • setにも使える
  • 「key=len」とすると比較対象が len(各要素) になる。
 b0 = sorted(set(bits.split('1')) - {''})
 b1 = sorted(set(bits.split('0')) - {''})
 unit = len(b1[0]) if b0==[] or len(b1[0]) <= len(b0[0]) else len(b0[0])

最初は上記のように書いていたのが、keyを使うことで ↓ こうなる

unit = len(sorted(set(bits.split('1') + bits.split('0')) - {''}, key = len)[0])