英文:
python string parsing issues when saving sql commands to file
问题
以下是代码部分的翻译:
我有字典数据,正在循环遍历以构建 PostgreSQL 的 `INSERT` 命令,其中字典的父键是列名,父值是列值:
data = {
'id': 45,
'col1': "foo's",
'col2': {'dict_key': 5}
}
columns = ', '.join(data.keys())
# 用双引号替换单引号,以形成用于 PostgreSQL 列的 JSON 类型
data['col2'] = data['col2'].replace("'", '"')
with open("file.sql", "w") as f:
command = "INSERT INTO table1({}) VALUES {};"
f.write(command.format(columns, tuple(data.values())))
如果需要任何其他翻译或帮助,请随时告诉我。
英文:
I have dicts data I am looping through to form INSERT
commands for postgresql. where the parent keys of the dicts are the column names and the parent values are the column values:
data = {
'id': 45,
'col1': "foo's",
'col2': {'dict_key': 5}
}
columns = ', '.join(data.keys())
# replace single quote with double to form a json type for psql column
data['col2'] = data['col2'].replace("'", '"')
with open("file.sql", "w") as f:
command = "INSERT INTO table1({}) VALUES {};"
f.write(command.format(columns, tuple(data.values()))
The problem is that the output of this is not formatted correctly for sql to execute. This is the output of the above:
INSERT INTO table1(id, col1, col2) VALUES (45, "foo's", '{"dict_key":5}');
The json field is formatted correctly with the single quotes around the value. But col2
keeps the double quotes if the string in col2
contains a single quote. This is a problem because postgresql requires single quotes to identify TEXT
input.
Is there a better way to parse data into psql
insert commands?
答案1
得分: 1
Did you try using json.dump()
and repr()
?
columns = ', '.join(data.keys())
data['col1'] = repr(data['col1'])
data['col2'] = json.dumps(data['col2'])
...
英文:
Did you try using json.dump()
and repr()
?
columns = ', '.join(data.keys())
data['col1'] = repr(data['col1'])
data['col2'] = json.dumps(data['col2'])
...
答案2
得分: 0
这似乎是Python中的一种限制(或者说是一种实现细节),涉及到字符串或str
的__repr__()
方法的定义。
尝试运行以下示例代码:
value = 'wont fix'; assert f'{value!r}' == "'wont fix'"
value = 'won\'t fix'; assert f'{value!r}' == "\"won't fix\""
可以看到,在字符串的repr
中,单引号是首选的,除非字符串本身包含单引号 - 在这种情况下,会使用双引号来包装字符串的repr
。
一个“快速而简单”的解决方案是实现一个自定义的字符串子类,名为SQStr
,它有效地覆盖了默认的repr
,始终使用单引号来包装字符串:
class SQStr(str):
def __repr__(self):
value = self.replace("'", r"\'")
return f"'{value}'"
如果您还想支持双转义的单引号,比如r"\\'"
,可以使用以下代码:
class SQStr(str):
def __repr__(self, _escaped_sq=r"\'", _tmp_symbol="|+*+|",
_default_repr=str.__repr__):
if "'" in self:
if _escaped_sq in self:
value = (self
.replace(_escaped_sq, _tmp_symbol)
.replace("'", _escaped_sq)
.replace(_tmp_symbol, r"\\'"))
else:
value = self.replace("'", _escaped_sq)
return f"'{value}'"
# 否则,字符串不包含单引号,所以我们可以使用默认的str.__repr__()
return _default_repr(self)
现在似乎可以按预期工作:
value = 'wont fix'; assert f'{SQStr(value)!r}' == "'wont fix'"
value = 'won\'t fix'; assert f'{SQStr(value)!r}' == r"'won\'t fix'"
# 可选
value = r"won't fix, won\'t!"; assert f'{SQStr(value)!r}' == r"'won\'t fix, won\\'t!'"
英文:
This appears to be a limitation (or rather an implementation detail) in Python, with how the __repr__()
for strings or str
is defined.
Try this sample code out:
value = 'wont fix'; assert f'{value!r}' == "'wont fix'"
value = 'won\'t fix'; assert f'{value!r}' == '"won\'t fix"'
As can be seen, single quotes are preferred in the repr
for strings, unless the string itself contains a single quote - in that case, double quotes are used to wrap the repr
for the string.
A "quick and dirty" solution is to implement a custom string subclass, SQStr
, which effectively overrides the default repr
to always wrap a string with single quotes:
class SQStr(str):
def __repr__(self):
value = self.replace("'", r"\'")
return f"'{value}'"
If you want to also support double-escaped single quotes like r"\\\'"
, then something like this:
class SQStr(str):
def __repr__(self, _escaped_sq=r"\'", _tmp_symbol="|+*+|",
_default_repr=str.__repr__):
if "'" in self:
if _escaped_sq in self:
value = (self
.replace(_escaped_sq, _tmp_symbol)
.replace("'", _escaped_sq)
.replace(_tmp_symbol, r"\\\'"))
else:
value = self.replace("'", _escaped_sq)
return f"'{value}'"
# else, string doesn't contain single quotes, so we
# can use the default str.__repr__()
return _default_repr(self)
Now it appears to work as expected:
value = 'wont fix'; assert f'{SQStr(value)!r}' == "'wont fix'"
value = 'won\'t fix'; assert f'{SQStr(value)!r}' == r"'won\'t fix'"
# optional
value = r"won't fix, won\'t!"; assert f'{SQStr(value)!r}' == r"'won\'t fix, won\\\'t!'"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论