python-3.x - 将代理对转换为表情符号 - python3
问题描述
我在另一个主题上找到了类似问题的解决方案,但不幸的是它对我不起作用。这是我的问题:
我正在从我想在另一个文件中搜索的代理对 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 循环中,我正在检查 line 是否包含 surrogatepairs unicode,如果它是真的,那么我想将这个 surrogatepair unicode 打印为表情符号 - 这就是我编码和解码这个“i”值的原因,它是 str:(解决方案来自:如何在 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
因此,当我启动程序时,它仍然将 surrogatepairs unicode 打印为 str,而不是 emoji,但是当我自己将 surrogatepair unicode 输入打印函数时,它可以工作:
print("\uD83C\uDFF3".encode("utf-16", "surrogatepass").decode("utf-16", "surrogatepass"))
#printing:
#
我究竟做错了什么?我试图从这个 i 和另一个解决方案中制作字符串,但它仍然不起作用。
编辑:
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
所以我的代理对被替换了,但是我的波兰字符被一些奇怪的东西替换了。
解决方案
你走在正确的轨道上。您尝试中断的内容是因为您在阅读文件后在“str”中拥有的不是“代理对” - 相反,它们是代理对的反斜杠编码代码点,编码为文本。
也就是说:文件中的序列“5c 75 44 38 33 44”是实际的 ascii 字符“\uD83D”(总共 6 个字符),而不是代理代码点 0xD83D(正确解码后,它与下一个代理一起“ \uDE0D" 将是字符串中的单个字符)。
我说你在正确的轨道上的部分是:你真的必须将它编码成一个字节序列,然后将它解码回来。问题是您必须使用“latin1”对其进行编码(只是为了尝试保留字符串上的任何其他非 ascii 字符 - 如果您的代码点无法在 latin1 中表示,它可能会中断),然后用特殊的“unicode 转义”编解码器。或charmap编码,它将保留字符串上的其他字符,然后使用相同的编解码器将其解码回来。此时,两个代理字符都将是 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 escape”并将其解码回来 - 这会将文件中扩展的人类可读“\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 ))
推荐阅读
- reactjs - ReactJS 如何调用打开简单模态的函数?
- c# - 方法没有重载 ... 需要 10 个参数。但是参数/参数匹配
- lua - Lua 中的代码注入是否可以仅使用变量定义来执行?
- opengl - 如何在 WSL 上更新 OpenGL 通行证 2.1 版?
- r - 渲染后重新隐藏条件闪亮输出
- concatenation - *open* 工作簿上的间接和连接 #ref 错误
- python - 如何在不知道参数名称的情况下将参数提供给多参数函数?Python
- typescript - 使用 nest.js 在 AWS Lambda 中获取 Cognito 数据(即 requestContext)
- python - 如何在pygame中使用相同的类创建独立工作的重复精灵?
- chart.js - ChartJS 如何提供对象数组作为数据集?