0
1

More than 1 year has passed since last update.

Python で バイト文字列をサニタイズ

Last updated at Posted at 2023-01-26

通信などで取得したデータとして、バイト列

data= b'@-79,8,7 251 507 10146 1404 152 3700 70b3d559e01d25a3\r\n'

がある。
これを処理する前にサニタイズし、決まったフォーマットでデータを採取しよう。

環境

  • Python 3.9.2
  • LANG=en_GB.UTF-8

最後の改行を rstrip で削除する

まずは、最後の改行。もし改行コードがあったりなかったりLFだったりCRLFだったりということを許容しないといけない場合は、右端に \r ないし \n を削除しておきたい。

rstrip を使うとすると バイト列で処理

  data2 = data.rstrip(b'\r\n')

ないし str で処理

  data2 = data.decode().rstrip('\r\n')

となる。

しかしながら後者はもし受信データが文字化けして以下のようになった場合

data= b'@-83,7,7 257 497 10153 423 \x00\x7F\xEF\xFE\xFF\r'

以下のようにエラーになる。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xef in position 29: invalid continuation byte

エラーを対策することもできるが、バイト列で処理するのが確実かな?

最後に改行が付いていた特定のキャラクタセットかどうか判定する

@,スペース、ハイフン、カンマ、数字(0〜9)、英小文字(a〜f) であるかどうかの判定

先に rstrip で \r\n を削除した。正規表現の書き方で[\r\n]* なので、改行の有無、個数や並び順を問わなかった。今回はそうではなく、最後が \r\n であるかどうかを厳密にチェックする。

if not r  if not re.fullmatch(b'[0-9a-f@ \-,]+\r\n', data):
    print("illeagal caracter error", file=sys.stderr)

決まったフォーマットのデータを抽出する

# 前半の3パラメータを取得
data2=( re.match( rb'^@([-0-9]+)'   # 行頭の@に続く符号付整数
                   +b',([-0-9]+)'   # カンマで区切られた2つ目の整数
                   +b',([-0-9]+)'   # カンマで区切られた3つ目の整数
            , data))
if ( None == data2 ):
    print("Not match error",file=sys.stderr)
    exit()
print (data2.group(1),data2.group(2),data2.group(3))

て、決まったフォーマットで並んだデータを取得。

スペース区切りのデータを抽出する

# 後半のスペース区切りデータを取得する
data3=( re.findall( rb' ([-0-9abcdef]+)',data))   # スペース区切りフィールド
print(len(data3))
if (7 == len(data3)):
    print(data3)
else:
    print("Value error", file=sys.stderr)
    exit()

スペースで区切られたデータを取得する。「決まったフォーマットのデータを抽出する」の方が厳密だけど、スペースの個数が可変な場合や、フィールドにより10進/16進が決まってない、フィールドの個数が可変などの場合はこちらの方がフレキシブル。

全部まとめたもの

#!/usr/bin/env python3
import re
import sys
# 受信電文例
data= b'@-83,7,7 257 497 10153 423 152 3700 70b3d559e01d25a3\r\n'
#data= b'@-83,7,7 257 497 10153 423 \x00\x7F\xEF\xFE\xFF\r\n'
#data= b'@-83,7,7 257 497 10153 423 \x00\x7F\xEF\xFE\xFF\r'
print(data)

# 不必要な文字セットが含まれておらず、最後が \r\n で終わっているかチェック
if not re.fullmatch(b'[0-9a-f@ \-,]+\r\n', data):
    print("illeagal caracter error", file=sys.stderr)
    exit()

# 前半の3パラメータを取得
data2=( re.match( rb'^@([-0-9]+)'   # 行頭の@に続く符号付整数
                   +b',([-0-9]+)'   # カンマで区切られた2つ目の整数
                   +b',([-0-9]+)'   # カンマで区切られた3つ目の整数
            , data))
if ( None == data2 ):
    print("Not match error",file=sys.stderr)
    exit()
print (data2.group(1),data2.group(2),data2.group(3))

# 後半のスペース区切りデータを取得する
data3=( re.findall( rb' ([-0-9abcdef]+)',data))   # スペース区切りフィールド
print(len(data3))
if (7 == len(data3)):
    print(data3)
else:
    print("Value error", file=sys.stderr)
    exit()

実行結果

$ python3 encodetest.py 
b'@-83,7,7 257 497 10153 423 152 3700 70b3d559e01d25a3\r\n'
b'-83' b'7' b'7'
7
[b'257', b'497', b'10153', b'423', b'152', b'3700', b'70b3d559e01d25a3']


0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1