亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Python 中散列一個整數以匹配 Oracle 的 STANDARD_HASH

在 Python 中散列一個整數以匹配 Oracle 的 STANDARD_HASH

呼啦一陣風 2021-12-29 10:48:10
在 Oracle 中,我的數據已通過將整數傳遞給“STANDARD_HASH”來進行散列,如下所示。如何使用 Python 獲得相同的哈希值?當整數傳遞給 STANDARD_HASH 時,在 Oracle 中產生結果:SELECT STANDARD_HASH(123, 'SHA256') FROM DUAL;# A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F傳入字符串時在 Python 中的結果:import hashlibhashlib.sha256(str.encode(str(123))).hexdigest().upper()# A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3# I want to modify this function to get the hash value above.也許這些信息也會有所幫助。我無法更改 Oracle 端的任何內容,但如果可以,我會將列轉換為CHAR,它會提供與我當前的 Python 實現相同的值。下面是一個例子。當字符串傳遞給 STANDARD_HASH 時,在 Oracle 中的結果:SELECT STANDARD_HASH('123', 'SHA256') FROM DUAL;# A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3 (matches Python result)我做了幾次嘗試,比如簡單地將一個整數傳遞給 Python,但這會導致需要一個字符串的錯誤。我還搜索了一種對整數進行編碼的方法,但沒有取得任何進展。
查看完整描述

2 回答

?
至尊寶的傳說

TA貢獻1789條經驗 獲得超10個贊

Oracle 以自己的內部格式表示數字,可以使用dump()Oracle 中的函數查看。例如,


SELECT dump(123) FROM dual;

Typ=2 Len=3: 194,2,24

因此,要在 Python 中散列一個數字并獲得與在 Oracle 中相同的結果,您需要將 Python 數字轉換為一組字節,就像 Oracle 在其內部所做的那樣。


可以在此處找到對 Oracle 使用的內部邏輯的良好分析。這是正確的,有一個與終止負數有關的小遺漏。此外,它是從從字節解碼Oracle 數字的角度編寫的。在我們的例子中,我們需要將Oracle 數字編碼為其內部字節格式。盡管如此,我在形成這個答案時廣泛使用了它。


下面的代碼顯示了一個 Python 函數,to_oracle_number(),它將返回一個整數數組,該數組具有與 Oracle 數據庫計算的數字相同的字節表示形式。它應該處理任何數字(正數、負數、小數、零等)。


最底部的代碼還顯示了如何調用此函數并對其結果進行散列以獲得與在 Oracle 數據庫中計算的相同的散列值,我認為這是您問題的核心。


注意:該函數期望您要轉換的數字作為字符串傳入,以避免精度損失。


import math

import decimal

import hashlib


def to_oracle_number( nstr ):

  # define number n that we want to convert

  n = decimal.Decimal(nstr)


  # compute exponent (base 100) and convert to Oracle byte along with sign

  #print (abs(n))

  l_exp = 0

  l_len = 0


  l_abs_n = abs(n)



  if l_abs_n != 0:

    l_exp = math.floor(math.log(l_abs_n,100))

    # Oracle adds 1 to all bytes when encoding

    l_exp = l_exp + 1

    # Oracle adds 64 to exponent whe encoding

    l_exp = l_exp + 64


  if n < 0:

    # take 1's complement of exponent so far (bitwise xor)

    l_exp = (l_exp ^ 127)


  if n >= 0:

    # add sign bit.  zero is considered positive.

    l_exp = l_exp + 128


  l_bytes = []

  l_bytes.append(l_exp)


  l_len = l_len + 1   # exponent and sign take 1 byte


  l_whole_part = str(int(l_abs_n))

  # make sure there is an even number of digits in the whole part

  if len(l_whole_part) % 2 == 1:

    l_whole_part = '0' + l_whole_part


  # get the fractional digits, so if 0.01234, just 01234

  l_frac_part = str(l_abs_n - int(l_abs_n))[2:]

  # make sure there is an even number of digits in the fractional part

  if len(l_frac_part) % 2 == 1:

    l_frac_part = l_frac_part + '0'


  l_mantissa = l_whole_part + l_frac_part


  # chop off leading 00 pairs

  while l_mantissa[0:2] == '00':

    l_mantissa = l_mantissa[2:]


  # chop off trailing 00 pairs

  while l_mantissa[-2:] == '00':

    l_mantissa = l_mantissa[:-2]


  # compute number of 2-character chunks

  l_chunk_count = int(len(l_mantissa) / 2)


  l_chunks = '';


  for i in range(0, l_chunk_count):

    l_chunk = int(l_mantissa[i*2:i*2+2])

    if n < 0:

      # for negative numbers, we subtract from 100

      l_chunk = 100-l_chunk


    # Oracle adds 1 to all bytes

    l_chunk = l_chunk + 1


    # Add the chunk to our answer

    l_chunks = l_chunks + ',' + str(l_chunk)

    l_bytes.append(l_chunk)

    l_len = l_len + 1   # we have computed one more byte

    #print (str(i) + ':' + str(l_chunk))


  if n < 0 and l_len < 21:

    # terminating negative numbers always end in byte 102 (do not know why)

    l_chunks = l_chunks + ',102'

    l_bytes.append(102)

    l_len = l_len + 1


  l_computed_dump = 'Typ=2 Len=' + str(l_len) + ': ' + str(l_exp) + l_chunks

  print  (l_computed_dump)

  print  (l_bytes)


  return l_bytes



# test it


m = hashlib.sha256()

b = bytes(to_oracle_number('123'))  # pass a string so no precision errors

m.update(b)

print(m.hexdigest().upper())

輸出

Typ=2 Len=3: 194,2,24

[194, 2, 24]

A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F


查看完整回答
反對 回復 2021-12-29
?
慕蓋茨4494581

TA貢獻1850條經驗 獲得超11個贊

警告:該線程的原始解決方案來自@Matthew McPeak's,這就是應該得到獎勵的答案,下面你會發現一個稍微修改過的版本,但我在他的算法中添加了一些重構:


import math

import decimal

import hashlib



def to_oracle_number(nstr):

    n = decimal.Decimal(nstr)


    # compute exponent (base 100) and convert to Oracle byte along with sign

    l_exp, l_len, l_abs_n = 0, 0, abs(n)


    if l_abs_n != 0:

        l_exp = math.floor(math.log(l_abs_n, 100)) + 65


    l_exp = (l_exp ^ 127) if n < 0 else l_exp + 128

    l_bytes = [l_exp]

    l_len += 1   # exponent and sign take 1 byte

    l_whole_part = str(int(l_abs_n))


    # make sure there is an even number of digits in the whole part

    if len(l_whole_part) % 2 == 1:

        l_whole_part = '0' + l_whole_part


    # get the fractional digits, so if 0.01234, just 01234

    l_frac_part = str(l_abs_n - int(l_abs_n))[2:]


    # make sure there is an even number of digits in the fractional part

    if len(l_frac_part) % 2 == 1:

        l_frac_part += '0'


    l_mantissa = l_whole_part + l_frac_part


    # chop off leading 00 pairs

    while l_mantissa[0:2] == '00':

        l_mantissa = l_mantissa[2:]


    # chop off trailing 00 pairs

    while l_mantissa[-2:] == '00':

        l_mantissa = l_mantissa[:-2]


    # compute number of 2-character chunks

    l_chunks = ''


    for i in range(0, int(len(l_mantissa) / 2)):

        l_chunk = int(l_mantissa[i * 2:i * 2 + 2])

        if n < 0:

            l_chunk = 100 - l_chunk


        l_chunk += 1

        l_chunks = f"{l_chunks},l_chunk"

        l_bytes.append(l_chunk)

        l_len += 1


    if n < 0 and l_len < 21:

        # terminating negative numbers always end in byte 102 (do not know why)

        l_chunks += ',102'

        l_bytes.append(102)

        l_len += 1


    # bytes(l_bytes)l_computed_dump = f"Typ=2 Len={l_len}: {l_exp}{l_chunks}"

    m = hashlib.sha256()

    m.update(bytes(l_bytes))

    return m.hexdigest().upper()



if __name__ == '__main__':

    assert to_oracle_number('123') == "A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F"



查看完整回答
反對 回復 2021-12-29
  • 2 回答
  • 0 關注
  • 202 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號