59

最も簡単な方法は正規表現を使用することですが、このチェックを行う方法は他にあるのではないかと思います。

なぜこれが必要なのですか?SIMカードからテキストメッセージ(SMS)を読み取るPythonスクリプトを書いています。状況によっては、16進メッセージが到着し、それらに対して何らかの処理を行う必要があるため、受信したメッセージが16進であるかどうかを確認する必要があります。

次のSMSを送信する場合:

Hello world!

そして私のスクリプトは

00480065006C006C006F00200077006F0072006C00640021

しかし、状況によっては、通常のテキストメッセージ(16進数ではない)を受信します。だから私はifhexコントロールをする必要があります。

Python2.6.5を使用しています。

アップデート:

その問題の理由は、(どういうわけか)私が送信hexしたメッセージは、オペレーターによって送信されたメッセージ(情報メッセージと広告)が通常の文字列として受信されているのと同じように受信されるためです。そこで、チェックを行い、メッセージが正しい文字列形式であることを確認することにしました。

いくつかの追加の詳細:私はHuawei3GモデムとPyHumodを使用してSIMカードからデータを読み取ります。

私の状況に対する可能な最善の解決策:

このような文字列を処理する最良の方法は、a2b_hex(aka unhexlify)とutf-16 big endian encoding(@JonasWielickiが述べたように)を使用することです。

from binascii import unhexlify  # unhexlify is another name of a2b_hex

mystr = "00480065006C006C006F00200077006F0072006C00640021"
unhexlify(mystr).encode("utf-16-be")
>> u'Hello world!'
4

13 に答える 13

101

(1)int( )の使用はこれにうまく機能し、Pythonがすべてのチェックを行います:)

int('00480065006C006C006F00200077006F0072006C00640021', 16)
6896377547970387516320582441726837832153446723333914657L

動作します。失敗した場合はValueError例外が発生します。

簡単な例:

int('af', 16)
175

int('ah', 16)
 ...
ValueError: invalid literal for int() with base 16: 'ah'

(2)の方法は、データをトラバースし、すべての文字が0..9との範囲内にあることを確認することa-f/A-Fです。string.hexdigits( )は大文字と小文字の両方'0123456789abcdefABCDEF'を含むため、これに役立ちます。

import string
all(c in string.hexdigits for c in s)

文字列のデータの有効性に基づいて、Trueまたはそのいずれかを返します。Falses

簡単な例:

s = 'af'
all(c in string.hexdigits for c in s)
True

s = 'ah'
all(c in string.hexdigits for c in s)
False

@ScottGriffithsが以下のコメントに正しく記載しているように、int()文字列が先頭に含まれている場合、このアプローチは機能しますが、文字ごと0xのチェックは失敗します。また、文字のセットに対するチェックは文字の文字列よりも高速ですが、短いSMS文字列でこれが問題になるかどうかは疑わしいです。ただし、それらの多く(多く!)を順番に処理する場合は、stringhexditigsをセットに変換できます。とset(string.hexdigits)

于 2012-07-21T12:41:50.783 に答える
28

あなたはできる:

  1. 文字列に16進数(0…9、A…F)のみが含まれているかどうかをテストします
  2. 文字列を整数に変換して、失敗するかどうかを確認してください。

コードは次のとおりです。

import string
def is_hex(s):
     hex_digits = set(string.hexdigits)
     # if s is long, then it is faster to check against a set
     return all(c in hex_digits for c in s)

def is_hex(s):
    try:
        int(s, 16)
        return True
    except ValueError:
        return False
于 2012-07-21T12:43:41.373 に答える
21

私はopが正規表現に言及していることを知っていますが、完全を期すためにそのようなソリューションを提供したいと思いました。

def is_hex(s):
    return re.fullmatch(r"^[0-9a-fA-F]$", s or "") is not None

パフォーマンス

ここで提案するさまざまなソリューションのパフォーマンスを評価するために、Pythonのtimeitモジュールを使用しました。入力文字列は、 3つの異なる長さ10、、、:に対してランダムに生成されます。1001000

s=''.join(random.choice('0123456789abcdef') for _ in range(10))

Levonのソリューション:

# int(s, 16)
  10: 0.257451018987922
 100: 0.40081690801889636
1000: 1.8926858339982573

# all(_ in string.hexdigits for _ in s)
  10:  1.2884491360164247
 100: 10.047717947978526
1000: 94.35805322701344

他の答えは、これら2つのバリエーションです。正規表現の使用:

# re.fullmatch(r'^[0-9a-fA-F]$', s or '')
  10: 0.725040541990893
 100: 0.7184272820013575
1000: 0.7190397029917222

したがって、適切なソリューションを選択するかどうかは、入力文字列の長さと、例外を安全に処理できるかどうかによって異なります。ValueError正規表現は確かに大きな文字列をはるかに高速に処理します(そしてオーバーフロー時にをスローしません)がint()、短い文字列の勝者です。

于 2015-12-14T06:35:04.483 に答える
5

文字列の設定への変換とサブセットのチェックに基づくもう1つの単純で短い解決策(「0x」プレフィックスをチェックしません):

import string
def is_hex_str(s):
    return set(s).issubset(string.hexdigits)

詳細はこちら

于 2018-12-27T10:20:27.983 に答える
3

別のオプション:

def is_hex(s):
    hex_digits = set("0123456789abcdef")
    for char in s:
        if not (char in hex_digits):
            return False
    return True
于 2013-01-24T18:48:35.603 に答える
2

上記で提案されたソリューションのほとんどは、10進数セットが16進数セットのサブセットであるため、10進数整数も16進数としてデコードされる可能性があることを考慮していません。したがって、Pythonは喜ん123でそれを16進数と0123見なします。

>>> int('123',16)
291

これは当たり前のように聞こえるかもしれませんが、ほとんどの場合、実際に16進数でエンコードされたもの、たとえばハッシュであり、 16進数でデコードできるものは探していません。したがって、おそらくより堅牢なソリューションでは、16進文字列の長さが均等かどうかもチェックする必要があります。

In [1]: def is_hex(s):
   ...:     try:
   ...:         int(s, 16)
   ...:     except ValueError:
   ...:         return False
   ...:     return len(s) % 2 == 0
   ...: 

In [2]: is_hex('123')
Out[2]: False

In [3]: is_hex('f123')
Out[3]: True
于 2017-04-29T19:42:24.600 に答える
1

これは、文字列が「0x」または「0X」で始まる場合をカバーします:[0x | 0X] [0-9a-fA-F]

d='0X12a'
all(c in 'xX' + string.hexdigits for c in d)
True
于 2018-04-16T21:10:22.093 に答える
0

あなたが真か偽かを判断しようとしているPythonを使用して、私はLevonのメソッド1よりもeumeroのis_hexメソッドを使用します。次のコードには落とし穴が含まれています...

if int(input_string, 16):
    print 'it is hex'
else:
    print 'it is not hex'

ゼロはFalseと評価されるため、文字列「00」は16進数ではないと誤って報告されます。

于 2014-05-13T20:09:49.407 に答える
0

上記のすべての正規表現にはほぼ同じ時間がかかったので、ほとんどの時間は文字列を正規表現に変換することに関連していたと思います。以下は、正規表現をプリコンパイルしたときに取得したデータです。

int_hex  
0.000800 ms 10  
0.001300 ms 100  
0.008200 ms 1000  

all_hex  
0.003500 ms 10  
0.015200 ms 100  
0.112000 ms 1000  

fullmatch_hex  
0.001800 ms 10  
0.001200 ms 100  
0.005500 ms 1000
于 2019-07-10T22:43:45.070 に答える
0

接頭辞付きの16進数または2進数と10進数を検証するパターンが必要な場合の簡単な解決策

\b(0x[\da-fA-F]+|[\d]+|0b[01]+)\b

サンプル:https ://regex101.com/r/cN4yW7/14

次にint('0x00480065006C006C006F00200077006F0072006C00640021', 0)、Pythonで実行すると6896377547970387516320582441726837832153446723333914657が得られます

ベース0は、プレフィックス推測動作を呼び出します。これは私に多くの面倒を省きました。それが役に立てば幸い!

于 2020-05-22T22:06:01.583 に答える
0

ほとんどのソリューションは、プレフィックス付きの文字列を適切にチェックしていません0x

>>> is_hex_string("0xaaa")  
False  
>>> is_hex_string("0x123")  
False  
>>> is_hex_string("0xfff")  
False  
>>> is_hex_string("fff")  
True  
于 2021-08-25T03:19:28.450 に答える
0

これが私の解決策です:

def to_decimal(s):
    '''input should be int10 or hex'''
    isString = isinstance(s, str)
    if isString:
        isHex = all(c in string.hexdigits + 'xX' for c in s)
        return int(s, 16) if isHex else int(s)
    else:
        return int(hex(s), 16)

a = to_decimal(12)
b = to_decimal(0x10)
c = to_decimal('12')
d = to_decimal('0x10')
print(a, b, c, d)
于 2022-01-28T05:06:21.470 に答える
-1

Python3では、次のことを試しました。

def is_hex(s):
    try:
        tmp=bytes.fromhex(hex_data).decode('utf-8')
        return ''.join([i for i in tmp if i.isprintable()])
    except ValueError:
        return ''

方法よりも優れているはずです:int(x、16)

于 2014-12-04T15:27:06.717 に答える