【问题标题】:General Python Unicode / ASCII Casting Issue Causing Trouble in Pyorient在 Pyorient 中导致问题的一般 Python Unicode / ASCII 转换问题
【发布时间】:2016-09-29 04:54:05
【问题描述】:

更新:我根据 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 上完美地创建了数百条记录。但是,我认为问题不一定是 pyorient 特定问题,因为我认为它在特定记录上失败的原因是因为 Ono.absolute_address 元素具有 pyorient 不知何故窒息的 unicode 字符。

我要创建的记录的 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

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

【问题讨论】:

  • 您能否向我们展示您的数据库架构(如果有)。 Nodes.Abs_Address 索引是如何声明的?
  • 当然,我使用 OrientDB studio gui 创建了它。它是一个字符串类型。如果您正在寻找更具体的东西,请告诉我如何从数据库中获取它,我很乐意为您获取它。我是 OrientDB 的新手。谢谢!
  • 关于字符串类型/编码也有类似的问题,见:stackoverflow.com/questions/7381718
  • 谢谢,Laurent,但我认为这并不能完全回答这个问题。我希望我知道问题出在 python 还是 OrientDB 中。我的字符串不适合 ascii 编码,因为不幸的是它使用了 \u2013 字符。我尝试使用快速而肮脏的查找和替换该字符,它本质上是一个破折号或减号 (.replace("–", "-")),如下所示:stackoverflow.com/questions/20329896/python-2-7-character-u2013 但失败了太...给我来自python的错误,即ascii编解码器无法解码位置0的字节0xe2:序数不在范围内(128)。
  • 替换 EN DASH (U+2013):u'/u/c/2/a1\u20132'.replace(u"\u2013", u"-")=> u'/u/c/2/a1-2'。它应该工作。您也应该替换 'Value': u'1\u20132' 中的 EN DASH。

标签: python string unicode orientdb pyorient


【解决方案1】:

我已经在 Python 3 上使用 pyorient 的开发分支和最新版本的 OrientDB 2.2.11 尝试了您的示例。如果我传递值而不转义它们,那么您的示例似乎对我有用,并且我得到了正确的值。

所以这个测试有效:

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'

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

【讨论】:

  • Anber,我遇到的更大的问题是,我有大量没有生成的文本,其中包含偶尔且不可预测的 unicode 字符。我只是从一个巨大的 xml 文件中提取文本,将其存储在一个变量中,将其传递给我上面显示的数据结构,然后尝试通过 pyorient 添加它。我喜欢你使用 JSON 编码的想法......但我无法找到和替换特定的字符,因为我不知道它们会提前是什么。无论字符串中的内容如何,​​您认为您的方法会起作用吗?
  • 您似乎已经将 unicode 转义值保存到您的数据库中,因此您应该继续这样做,否则您的手会一团糟。因为您不知道哪些值会给您带来问题,所以您应该转义所有值。您需要确保在构造查询时,需要对非转义值进行两次转义,并在需要显示它们时将它们解码回原始值。我相信这会起作用,但您必须编写自己的单元测试才能确定。
猜你喜欢
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-07
  • 1970-01-01
  • 1970-01-01
  • 2012-11-02
  • 1970-01-01
相关资源
最近更新 更多