有没有办法通过 HQL/SQL 解析带有转义的 csv 字符串?
Is there a way to parse csv string with escapings via HQL/SQL?
我在解析存储在随后加载到 PostgreSQL 数据库中的 Hive table 列中的 csv 格式数据时遇到问题。我需要做的是从那里检索一些字段,但是,如果引用了逗号,则应将其视为要检索的数据的一部分;最重要的是,引号可以自己转义。这是我尝试过的方法、结果如何以及预期的输出结果:
考虑这个字符串:a,b,c,"d,e,1","dj+""17"""
输出应该是这样的:a b c d,e,1 dj+"17"
我尝试使用 regexp_extract
,如下所示:
regexp_extract(data,'(,?(".*?"|[^,]*)){1}',2)
.
它几乎按照我想要的方式工作,唯一的问题是它不能使用转义引号正常工作:它在我想要的基础上将 "dj+""17"""
拆分为 dj+ 17 <empty string>
去做。
我发现 Hive 允许您使用 CSVSerde 解决此类任务,但是,我只看到它在数据存储在文本文件中时被使用,而事实并非如此。这个问题有解决方法吗?
P.S.: 我在 Hive 和 Hadoop 方面总体上缺乏专业知识,所以我可能不了解某些原理和可用功能
可以用逗号分隔字符串,后跟偶数个引号或零个引号,如果逗号在引号内则不分隔。这仅在您只有平衡报价时才有效(每个报价都有相应的收盘价)。
代码(蜂巢):
with mytable as(
select 'a,b,c,"d,e,1","dj+""17"""' as original_string
)
select --remove quotes at the beginning and at the end of the string
regexp_replace(splitted[0],'^"(.*?)"$','') as col1,
regexp_replace(splitted[1],'^"(.*?)"$','') as col2,
regexp_replace(splitted[2],'^"(.*?)"$','') as col3,
regexp_replace(splitted[3],'^"(.*?)"$','') as col4,
regexp_replace(splitted[4],'^"(.*?)"$','') as col5
from
(
select split(original_string, ',(?=(?:[^"]*"[^"]*")*[^"]*$)') as splitted from mytable
)s;
结果:
col1 col2 col3 col4 col5
a b c d,e,1 dj+""17""
正则表达式 ',(?=(?:[^"]*"[^"]*")*[^"]*$)'
表示:
,
- 逗号
(?=
- 后跟组(零长度正向前看)开始
(?:[^"]*"[^"]*")
--non-capturing group consisting of 0+ non-quote, quote, 0+ non-quote, quote
*
组重复0+
$
- 字符串结尾
)
- 后面的组结束(正向展望)
要取消引用 "d,e,1"
等元素,使用表达式 regexp_replace(str,'^"(.*?)"$','')
。如果字符串有开始和结束引号,它会删除它们。
此外,您可能还想用单引号替换两个双引号,以将 dj+""17""
这样的值转换为 dj+"17"
。
我在解析存储在随后加载到 PostgreSQL 数据库中的 Hive table 列中的 csv 格式数据时遇到问题。我需要做的是从那里检索一些字段,但是,如果引用了逗号,则应将其视为要检索的数据的一部分;最重要的是,引号可以自己转义。这是我尝试过的方法、结果如何以及预期的输出结果:
考虑这个字符串:a,b,c,"d,e,1","dj+""17"""
输出应该是这样的:a b c d,e,1 dj+"17"
我尝试使用 regexp_extract
,如下所示:
regexp_extract(data,'(,?(".*?"|[^,]*)){1}',2)
.
它几乎按照我想要的方式工作,唯一的问题是它不能使用转义引号正常工作:它在我想要的基础上将 "dj+""17"""
拆分为 dj+ 17 <empty string>
去做。
我发现 Hive 允许您使用 CSVSerde 解决此类任务,但是,我只看到它在数据存储在文本文件中时被使用,而事实并非如此。这个问题有解决方法吗?
P.S.: 我在 Hive 和 Hadoop 方面总体上缺乏专业知识,所以我可能不了解某些原理和可用功能
可以用逗号分隔字符串,后跟偶数个引号或零个引号,如果逗号在引号内则不分隔。这仅在您只有平衡报价时才有效(每个报价都有相应的收盘价)。
代码(蜂巢):
with mytable as(
select 'a,b,c,"d,e,1","dj+""17"""' as original_string
)
select --remove quotes at the beginning and at the end of the string
regexp_replace(splitted[0],'^"(.*?)"$','') as col1,
regexp_replace(splitted[1],'^"(.*?)"$','') as col2,
regexp_replace(splitted[2],'^"(.*?)"$','') as col3,
regexp_replace(splitted[3],'^"(.*?)"$','') as col4,
regexp_replace(splitted[4],'^"(.*?)"$','') as col5
from
(
select split(original_string, ',(?=(?:[^"]*"[^"]*")*[^"]*$)') as splitted from mytable
)s;
结果:
col1 col2 col3 col4 col5
a b c d,e,1 dj+""17""
正则表达式 ',(?=(?:[^"]*"[^"]*")*[^"]*$)'
表示:
,
- 逗号
(?=
- 后跟组(零长度正向前看)开始
(?:[^"]*"[^"]*")
--non-capturing group consisting of 0+ non-quote, quote, 0+ non-quote, quote
*
组重复0+
$
- 字符串结尾
)
- 后面的组结束(正向展望)
要取消引用 "d,e,1"
等元素,使用表达式 regexp_replace(str,'^"(.*?)"$','')
。如果字符串有开始和结束引号,它会删除它们。
此外,您可能还想用单引号替换两个双引号,以将 dj+""17""
这样的值转换为 dj+"17"
。