一般的Python Unicode / ASCII转换问题导致Pyorient中出现问题

时间:2016-09-29 04:54:06

标签: python string unicode orientdb pyorient

更新:我根据Ivan Mainetti的建议在github上打开了一个问题。如果你想在那里称重,那就是:https://github.com/orientechnologies/orientdb/issues/6757

我正在开发一个基于OrienDB的数据库并使用python接口。我已经运气好了,但在处理某些unicode角色时,我遇到了一个似乎是驱动程序(pyorient)的问题。

我上传到数据库的数据结构如下所示:

new_Node = {'@Nodes':
                {
                    "Abs_Address":Ono.absolute_address,
                    'Content':Ono.content,
                    'Heading':Ono.heading,
                    'Type':Ono.type,
                    'Value':Ono.value
                }
}

我在OrientDB / pyorient上完美地创建了数百条记录。我不认为这个问题必然是一个特定的问题,因为我认为它在特定记录上失败的原因是因为Ono.absolute_address元素有一个unicode字符,pyorient在某种程度上令人窒息。

我想要创建的记录的abs_address为/ u / c / 2 / a1-2,但是当我将值传递给上面的数据结构时,我获得的节点是:

{'@Nodes': {'Content': '', 'Abs_Address': u'/u/c/2/a1\u20132', 'Type': 'section', 'Heading': ' Transferred', 'Value': u'1\u20132'}}

我认为不知怎的,我的问题是python是混合unicode和ascii字符串/字符?我对python并不熟悉并且没有声明类型,所以我希望这不是pyorient perse的问题,因为new_Node对象没有输出格式正确的字符串...... ?或者这是pyorient不喜欢unicode的实例?我把头发撕成了这个。任何帮助表示赞赏。

如果错误来自pyorient而不是某种文本编码,这里是与pyorient相关的信息。我正在使用此代码创建记录:

rec_position = self.pyo_client.record_create(14, new_Node)

这就是我得到的错误:

com.orientechnologies.orient.core.storage.ORecordDuplicatedException - Cannot index record Nodes{Content:,Abs_Address:null,Type:section,Heading: Transferred,Value:null}: found duplicated key 'null' in index 'Nodes.Abs_Address' previously assigned to the record #14:558

错误很奇怪,因为它表明后端数据库正在获取该地址的空对象。显然它确实为这个"地址创建了一个条目,"但这不是我想要它做的。我不知道为什么带有unicode的地址字符串在数据库中出现空...我可以通过orientDB studio使用我输入new_Node数据结构的确切字符串来创建...但我不能使用python做同样的事情。

有人帮忙吗?

编辑:

感谢Laurent,我已经将问题缩小到与unicode对象和pyorient有关的范围。每当我传递的变量是unicode类型时,pyorient适配器就会向OrientDB数据库发送一个空值。我确定导致问题的值是一个ndash符号,Laurent帮我用这个代码用减号替换它

.replace(u"\u2013",u"-")

然而,当我这样做时,pyorient获取unicode对象,然后将其作为空值传递...这不好。我可以通过使用str(...)重新编写字符串来解决这个短期问题,这似乎可以解决我当前的问题:

str(Ono.absolute_address.replace(u"\u2013",u"-"))

。问题是,我知道我的数据库数据中会有符号和其他不寻常的字符。我知道数据库支持unicode字符串,因为我可以手动添加它们或使用SQL语法来做我不能通过pyorient和python做的事情......我假设这是一个冒险的某个地方的投射问题,但我并不是真的确定在哪里。这似乎与此问题非常相似:http://stackoverflow.duapp.com/questions/34757352/how-do-i-create-a-linked-record-in-orientdb-using-pyorient-library

那里有人吗?蟒蛇神?幸运的s0bs? =)

1 个答案:

答案 0 :(得分:1)

我在python上使用最新版本的OrientDB 2.2.11尝试了Python 3上的示例。如果我在不转义值的情况下传递值,那么您的示例似乎对我有用,并且我得到了正确的值。

所以这个测试有效:

def test_test1(self):
    new_Node = {'@Nodes': {'Content': '',
                           'Abs_Address': '/u/c/2/a1–2',
                           'Type': 'section',
                           'Heading': ' Transferred',
                           'Value': u'1\u20132'}
                }

    self.client.record_create(14, new_Node)

    result = self.client.query('SELECT * FROM V where Abs_Address="/u/c/2/a1–2"')
    assert result[0].Abs_Address == '/u/c/2/a1–2'

我认为您可能会将unicode值保存为转义值,这就是事情变得棘手的问题。

我不相信自己更换值,所以我通常使用以下代码转义我发送给orientdb的unicode值:

import json
def _escape(string):
    return json.dumps(string)[1:-1]

以下测试将失败,因为转义的值与数据库中的转义值不匹配,因此不会返回任何记录:

def test_test2(self):
    new_Node = {'@Nodes': {'Content': '',
                           'Abs_Address': _escape('/u/c/2/a1–2'),
                           'Type': 'section',
                           'Heading': ' Transferred',
                           'Value': u'1\u20132'}
                }

    self.client.record_create(14, new_Node)

    result = self.client.query('SELECT * FROM V where Abs_Address="%s"' % _escape('/u/c/2/a1–2'))
    assert  result[0].Abs_Address.encode('UTF-8').decode('unicode_escape') == '/u/c/2/a1–2'

为了解决这个问题,你必须将值转义两次:

def test_test3(self):
    new_Node = {'@Nodes': {'Content': '',
                           'Abs_Address': _escape('/u/c/2/a1–2'),
                           'Type': 'section',
                           'Heading': ' Transferred',
                           'Value': u'1\u20132'}
                }

    self.client.record_create(14, new_Node)

    result = self.client.query('SELECT * FROM V where Abs_Address="%s"' % _escape(_escape('/u/c/2/a1–2')))
    assert  result[0].Abs_Address.encode('UTF-8').decode('unicode_escape') == '/u/c/2/a1–2'

此测试将成功,因为您现在将要求DB中的转义值。