如何从 pandas 数据帧中转义 json 值中的双引号进行解析?
How to escape double inverted commas in json values from pandas dataframe for parsing?
所以这是一个很长的问题,但请稍等,我会尽力解释我的问题:
我有一个数据框,其中一列的行为 json,我能够正确解析它们
id | email | phone no | details
-------------------------------------------------
0 10 | abc@g.com | 123 | {"name" : "John "Smart" Wick", "address" : "123 c "dumb" road"}
1 12 | xyz@g.com | 789 | {"name" : "Peter Parker", "address" : "L "check" street"}
我希望将此 json 分发到以下列:
id
email
phone no
name
address
10
abc@g.com
123
John "Smart" Wick
123 c "dumb" road
12
xyz@g.com
789
Peter Parker
L "check" street
要将 json 键分成列,我可以这样做:
# Check: 1
result = df.pop('details').apply(json.loads).apply(pd.Series).join(df)
这一直有效,直到我遇到像上面那样的情况,其中任何字段中的 json 值都有引号。该数据用于表示目的,实际上我有数百万条记录,'details' 列有 10+ key/value 对。
对于热修复,这是我所做的:
# check: 2
df['details'] = df['details'].str.replace('John "Smart" "Wick','John Smart Wick')
df['details'] = df['details'].str.replace('123 c "dumb" road','123 c dumb road')
df['details'] = df['details'].str.replace('L "check" street','L check street')
然后我 运行 #check: 1 处的代码,它工作正常,这次我再次替换它。在一百万条记录中,只有 2 条这样的情况会导致这样的问题破坏代码,所以我找到了那 2 条臭名昭著的记录,并通过热修复替换了数据以删除引号,然后在处理后重新引入它们。
我想要的是有一种方法,无论此类问题发生多少次,它都不会产生问题,并且可以轻松通过#check: 1 和 return 原始值,而无需我手动捕获此类记录并将其替换为 运行。我想知道正则表达式是否可以做到这一点,我尝试了一些东西,但这些都不够好并且不断抛出错误。
我能够在我的水平上解决这个问题,但是在 json key/value 对 pandas 数据框中的列中处理所有此类异常的通用方法将是一个很好的选择要学习的东西。我知道 json 在这里不干净,所以基本上是一种在任何此类情况下对其进行清理的方法,以便我们可以将 key/value 拆分为单独的列。
感谢您的帮助。
编辑:我也把它放在评论中,如果我添加转义字符,它就可以正常工作,如:
df['details'] = df['details'].str.replace('John "Smart" "Wick','John \"Smart\" Wick')
df['details'] = df['details'].str.replace('123 c "dumb" road','123 c \"dumb\" road')
df['details'] = df['details'].str.replace('L "check" street','L check \"check\" street')
这也可以,但它仍然需要我手动识别记录并为那些带有转义字符的记录添加替换命令。这可以在整个 'details' 列的循环中完成,以自我识别此类情况并在需要时添加转义字符吗?
由于字符串化的 JSON 中只有两个字段,您可以使用 上下文匹配 和正则表达式来确保匹配两个名称之间或字符串末尾的任何文本。
这是您可以用来匹配和捕获必要位的正则表达式:
(?s)("(?:name|address)"\s*:\s*")(.*?)(?="(?:\s*,\s*"(?:name|address)"|}$))
见regex demo。匹配项包含两个相邻的组,其中第一个组需要保持原样,第二组中的所有 "
个字符都应该加上文字反斜杠。
使用Series.str.replace
执行此操作:
import pandas as pd
df = pd.DataFrame(
{'text':['{"name" : "John "Smart" Wick", "address" : "123 c "dumb" road"}']}
)
rx = r'(?s)("(?:name|address)"\s*:\s*")(.*?)(?="(?:\s*,\s*"(?:name|address)"|}$))'
df['text'] = df['text'].str.replace(rx, lambda x: x.group(1) + x.group(2).replace('"',r'\"'), regex=True)
# -> df
# text
# 0 {"name" : "John \"Smart\" Wick", "address" : "123 c \"dumb\" road"}
所以这是一个很长的问题,但请稍等,我会尽力解释我的问题:
我有一个数据框,其中一列的行为 json,我能够正确解析它们
id | email | phone no | details
-------------------------------------------------
0 10 | abc@g.com | 123 | {"name" : "John "Smart" Wick", "address" : "123 c "dumb" road"}
1 12 | xyz@g.com | 789 | {"name" : "Peter Parker", "address" : "L "check" street"}
我希望将此 json 分发到以下列:
id | phone no | name | address | |
---|---|---|---|---|
10 | abc@g.com | 123 | John "Smart" Wick | 123 c "dumb" road |
12 | xyz@g.com | 789 | Peter Parker | L "check" street |
要将 json 键分成列,我可以这样做:
# Check: 1
result = df.pop('details').apply(json.loads).apply(pd.Series).join(df)
这一直有效,直到我遇到像上面那样的情况,其中任何字段中的 json 值都有引号。该数据用于表示目的,实际上我有数百万条记录,'details' 列有 10+ key/value 对。
对于热修复,这是我所做的:
# check: 2
df['details'] = df['details'].str.replace('John "Smart" "Wick','John Smart Wick')
df['details'] = df['details'].str.replace('123 c "dumb" road','123 c dumb road')
df['details'] = df['details'].str.replace('L "check" street','L check street')
然后我 运行 #check: 1 处的代码,它工作正常,这次我再次替换它。在一百万条记录中,只有 2 条这样的情况会导致这样的问题破坏代码,所以我找到了那 2 条臭名昭著的记录,并通过热修复替换了数据以删除引号,然后在处理后重新引入它们。
我想要的是有一种方法,无论此类问题发生多少次,它都不会产生问题,并且可以轻松通过#check: 1 和 return 原始值,而无需我手动捕获此类记录并将其替换为 运行。我想知道正则表达式是否可以做到这一点,我尝试了一些东西,但这些都不够好并且不断抛出错误。
我能够在我的水平上解决这个问题,但是在 json key/value 对 pandas 数据框中的列中处理所有此类异常的通用方法将是一个很好的选择要学习的东西。我知道 json 在这里不干净,所以基本上是一种在任何此类情况下对其进行清理的方法,以便我们可以将 key/value 拆分为单独的列。
感谢您的帮助。
编辑:我也把它放在评论中,如果我添加转义字符,它就可以正常工作,如:
df['details'] = df['details'].str.replace('John "Smart" "Wick','John \"Smart\" Wick')
df['details'] = df['details'].str.replace('123 c "dumb" road','123 c \"dumb\" road')
df['details'] = df['details'].str.replace('L "check" street','L check \"check\" street')
这也可以,但它仍然需要我手动识别记录并为那些带有转义字符的记录添加替换命令。这可以在整个 'details' 列的循环中完成,以自我识别此类情况并在需要时添加转义字符吗?
由于字符串化的 JSON 中只有两个字段,您可以使用 上下文匹配 和正则表达式来确保匹配两个名称之间或字符串末尾的任何文本。
这是您可以用来匹配和捕获必要位的正则表达式:
(?s)("(?:name|address)"\s*:\s*")(.*?)(?="(?:\s*,\s*"(?:name|address)"|}$))
见regex demo。匹配项包含两个相邻的组,其中第一个组需要保持原样,第二组中的所有 "
个字符都应该加上文字反斜杠。
使用Series.str.replace
执行此操作:
import pandas as pd
df = pd.DataFrame(
{'text':['{"name" : "John "Smart" Wick", "address" : "123 c "dumb" road"}']}
)
rx = r'(?s)("(?:name|address)"\s*:\s*")(.*?)(?="(?:\s*,\s*"(?:name|address)"|}$))'
df['text'] = df['text'].str.replace(rx, lambda x: x.group(1) + x.group(2).replace('"',r'\"'), regex=True)
# -> df
# text
# 0 {"name" : "John \"Smart\" Wick", "address" : "123 c \"dumb\" road"}