我已经编码了十六进制(设备ID):
9F1D8E8BA2194CD29CC744083914535A
转换为85位编码数字(等效转换):
T,irMU)?YQSB"#\'3>>Cq
这些都存储在spark数据框中。
问题是,当我尝试将其转换回(将列传递给UDF)时,它没有给我设备ID,在调试时我发现它给出的输出实际上是为:
T,irMU)?YQSB"#\\\'3>>Cq
这意味着实际的字符串会自动添加一个转义字符,然后对其进行解码。
这是udf,我写过要进行转换:
def convert_id(id):
id = id.replace("-", "")
return str(bs64.a85encode(bytearray.fromhex(id)))[2:-1]
udf_convert_id = udf(convert_id, StringType())
这是用于解码的:
def convert_docid2idfa(docId):
try:
docId = docId.replace('\\\\','\\')
id_str = bs64.a85decode(docId).hex()
idfa = id_str[:8]+"-"+id_str[8:12]+"-"+id_str[12:16]+"-"+id_str[16:20]+"-"+id_str[20:]
return idfa
except:
return docId
convert_docid2idfa_udf = udf(convert_docid2idfa, StringType())
我正在解码此版本,该版本已转义。
答案 0 :(得分:2)
ASCII85编码ID的 actual 值应为:
T,irMU)?YQSB"#'3>>Cq
该值中不应包含\
。错误的是您将a85encode()
结果转换为字符串:
str(bs64.a85encode(bytearray.fromhex(id)))[2:-1]
a85encode()
返回一个bytes
对象,您需要解码,以ASCII形式获得具有相同代码点的字符串值:
bs64.a85encode(bytearray.fromhex(id)).decode('ASCII')
str(bytesobject)
为您提供了易于调试的表示形式,可以安全地粘贴回Python代码中,因此任何'
字符都可以通过\
进行转义面前。您不想将此表示形式用于序列化。
请注意,您不需要bytearray
,一个常规的不可变bytes
对象就足以将十六进制ID解码为二进制字符串:
bs64.a85encode(bytes.fromhex(id)).decode('ASCII')
演示:
>>> import base64 as b64
>>> id = '9F1D8E8BA2194CD29CC744083914535A'
>>> encoded = bs64.a85encode(bytes.fromhex(id)).decode('ASCII')
>>> print(encoded)
T,irMU)?YQSB"#'3>>Cq
>>> b64.a85decode(encoded).hex()
'9f1d8e8ba2194cd29cc744083914535a'
如果您无法修复编码,则仍然可以使用unicode_escape
编解码器来修复损坏的值;首先将字符串编码为ASCII。您应该能够通过测试长度来检测到这样的损坏值,一个20字节的IDFA应该始终会导致一个20个字符的ASCII85字符串,而任何需要修复的内容都将被修复:
if len(docId) > 20:
docId = docId.encode('ascii').decode('unicode_escape')
decoded = b64.a85decode(docId).hex()
以上内容修复了通过对字节对象调用str()
引入的转义符:
>>> encoded
'T,irMU)?YQSB"#\'3>>Cq'
>>> botched = str(encoded.encode('ascii'))[2:-1]
>>> botched
'T,irMU)?YQSB"#\\\'3>>Cq'
>>> botched.encode('ascii').decode('unicode_escape')
'T,irMU)?YQSB"#\'3>>Cq'
>>> bs64.a85decode(botched.encode('ascii').decode('unicode_escape')).hex()
'9f1d8e8ba2194cd29cc744083914535a'
请注意,如果您使用的是IDFA值,则可以使用uuid.UUID()
class在表示形式之间进行转换:
from uuid import UUID
bs64.a85encode(UUID(hex=id).bytes).decode('ASCII')
进行编码,
str(UUID(bytes=bs64.a85decode(docId)))
返回带破折号的8-4-4-4-12十六进制字符串:
>>> from uuid import UUID
>>> id = '9F1D8E8B-A219-4CD2-9CC7-44083914535A'
>>> encoded = bs64.a85encode(UUID(hex=id).bytes).decode('ASCII')
>>> encoded
'T,irMU)?YQSB"#\'3>>Cq'
>>> str(UUID(bytes=bs64.a85decode(encoded)))
'9f1d8e8b-a219-4cd2-9cc7-44083914535a'