我在另一个主题上找到了类似问题的解决方案,但不幸的是,它不适用于我。 这是我的问题:
我正在用代理对unicode制作数据帧,我想在另一个文件中搜索它(例如:“ \ uD83C \ uDFF3”,“ \ u26F9”,“ \ uD83C \ uDDE6 \ uD83C \ uDDE8”):
with open("unicodes.csv", "rt") as csvfile:
emoticons = pd.read_csv(csvfile, names=["xy"])
emoticons = pd.DataFrame(emoticons)
emoticons = emoticons.astype(str)
接下来,我正在阅读带有文本的文件,其中某些行包含代理对unicode:
for chunk in pd.read_csv(path, names=["xy"], encoding="utf-8", chunksize=chunksize):
spam = pd.DataFrame(chunk)
spam = spam.astype(str)
在此for循环中,我正在检查行是否包含代理对unicode,如果为真,那么我想将此替代对unicode打印为表情符号-这就是为什么我要编码和解码该“ i”值,即str: (来自How to work with surrogate pairs in Python?的解决方案)
for i in emoticons.xy:
if spam["xy"].str.contains(i, regex=False).any():
print(i.encode('utf-16', 'surrogatepass').decode('utf-16'))
#printing:
#\uD83C\uDFF3
#\u26F9
#\uD83C\uDDE6\uD83C\uDDE8
因此,当我启动程序时,它仍然将替代代理对uni打印为str而不是表情符号,但是当我自己将替代对unicode输入到打印函数中时,它可以工作:
print("\uD83C\uDFF3".encode("utf-16", "surrogatepass").decode("utf-16", "surrogatepass"))
#printing:
#?
我在做什么错?我尝试通过此方法和其他解决方案制作字符串,但仍然无法正常工作。
编辑:
hexdump -C file.csv
00004b70 5c 75 44 38 33 44 5c 75 44 45 45 39 0a 5c 75 44 |\uD83D\uDEE9.\uD|
00004b80 38 33 44 5c 75 44 45 45 42 0a 5c 75 44 38 33 44 |83D\uDEEB.\uD83D|
00004b90 5c 75 44 45 45 43 0a 5c 75 44 38 33 44 5c 75 44 |\uDEEC.\uD83D\uD|
00004ba0 43 42 41 0a 5c 75 44 38 33 44 5c 75 44 45 38 31 |CBA.\uD83D\uDE81|
EDIT2: 因此,我发现了某种可行的方法,但仍需要改进: https://stackoverflow.com/a/54918256/4789281
我要转换的另一个文件中的文本为外观文件:
"O żółtku zapomniałaś \uD83D\uDE02"
"Piękny outfit \uD83D\uDE0D"
在执行此操作时,另一个主题中的建议是:
print(codecs.decode(i,encoding='unicode_escape',errors='surrogateescape').encode('utf-16', 'surrogatepass').decode('utf-16'))
我有这样的东西:
O żóÅtku zapomniaÅaÅ ?
PiÄkny outfit ?
所以我的代理配对被替换了,但是我的波兰字符被替换成了奇怪的东西。
答案 0 :(得分:0)
您的路线正确。 为什么要尝试中断,因为读取文件后在“ str”中的内容不是“代理对”,而是代理对的反斜杠编码代码点,编码为文本。
也就是说,文件中的序列“ 5c 75 44 38 33 44”是实际的ASCII字符“ \ uD83D”(总共6个字符),而不是替代代码点0xD83D(在正确解码后会与下一个代理“ \ uDE0D”将是您字符串中的单个字符。
我说的对的部分是:您确实必须将其编码为字节序列,然后再解码回去。错误的是,您必须使用“ latin1”对其进行编码(只是尝试保留字符串上的任何其他非ascii字符-如果您的代码点无法在latin1中表示,它可能会损坏),然后使用特殊的“ unicode转义”编解码器。或charmap编码,它将在字符串上保留您的 other 字符,然后使用相同的编解码器将其解码回去。届时,两个代理字符都将是文本,作为Python字符串中的两个字符:
In [16]: "\\uD83D\\uDE0D".encode("latin1").decode("unicode escape", "surrogatepass")
Out[16]: '\ud83d\ude0d'
坏消息是-这不是一个非常有效的STR-替代字符本身不应在内部表示中存在-而是应将它们组合为所需的最终字符。因此,尝试将其打印出来会失败:
In [19]: a = "\\uD83D\\uDE0D".encode("utf-8").decode("unicode escape")
In [20]: print(a)
---------------------------------------------------------------------------
UnicodeEncodeError Traceback (most recent call last)
<ipython-input-20-bca0e2660b9f> in <module>
----> 1 print(a)
UnicodeEncodeError: 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed
在这里使用“ surrogatepass”错误策略没有帮助-您将获得不可打印的字节序列。
因此,第二次必须对此进行“编码”和“解码”-这次,文本中的字符是实际的“替代”代码点,这些点将是有效的utf-16进行解码。因此,现在的路径是对该序列进行编码,使用“ surrogatepass”对这些字符进行暴力破解,然后从utf-16解码回来-最终将代理对理解为单个字符:
In [30]: a = "\\uD83D\\uDE0D".encode("unicode escape").decode("unicode escape")
In [31]: a
Out[31]: '\ud83d\ude0d'
In [32]: b = a.encode("utf-16", "surrogatepass").decode("utf-16")
In [33]: print(b)
?
总结:
您以utf-8文本格式读取文件,以读取其他可能的非ASCII字符, 将结果编码为“ unicode转义”并将其解码回-这将转换 在文件中扩展了人类可读的“ \ uXXXX”序列作为代理代码点。然后将其转换回utf-16,告诉Python忽略 代理,然后“原样”复制,然后从utf-16解码回去:
def decode_surrogate_ascii(txt):
interm = txt.encode("latin1").decode("unicode escape")
return interm.encode("utf-16", "surrogatepass").decode("utf-16")
您需要做的就是在数据框上感兴趣的列中应用上述功能:
emoticons = emoticons.apply(pd.Series(lambda row: (decode_surrogate_ascii(item) if isinstance(item, str) else item for item in row ))