如何使用模式获取子字符串并使用scala替换json值字段中的引号?

时间:2018-05-20 03:39:05

标签: scala apache-spark

我有很少的json消息,比如

{"column1":"abc","column2":"123","column3":qwe"r"ty,"column4":"abc123"}
{"column1":"defhj","column2":"45","column3":asd"f"gh,"column4":"def12d"}

我需要为column3值添加双引号,并使用scala将column3值中的双引号替换为单引号。

2 个答案:

答案 0 :(得分:0)

您在上面的评论中提到了

  
    

我在kafka中有大量的数据集。我正在尝试从kafka读取并使用scala通过spark写入hdfs。我正在使用json解析器但由于column3问题而无法解析。因此需要操纵消息以更改为json

  

所以你必须像问题一样收集畸形的jsons。我创建了一个列表

val kafkaMsg = List("""{"column1":"abc","column2":"123","column3":qwe"r"ty,"column4":"abc123"}""", """{"column1":"defhj","column2":"45","column3":asd"f"gh,"column4":"def12d"}""")

你正在通过Spark阅读它,所以你必须将rdds作为

val rdd = sc.parallelize(kafkaMsg)

所有你需要的是在格式错误的文本json中进行一些解析,使其成为有效的json字符串

val validJson = rdd.map(msg => msg.replaceAll("[}\"{]", "").split(",").map(_.split(":").mkString("\"", "\":\"", "\"")).mkString("{", ",", "}"))

validJson应该是

{"column1":"abc","column2":"123","column3":"qwerty","column4":"abc123"}
{"column1":"defhj","column2":"45","column3":"asdfgh","column4":"def12d"}

可以从validJson rdd 创建一个数据框作为

sqlContext.read.json(validJson).show(false)

应该给你

+-------+-------+-------+-------+
|column1|column2|column3|column4|
+-------+-------+-------+-------+
|abc    |123    |qwerty |abc123 |
|defhj  |45     |asdfgh |def12d |
+-------+-------+-------+-------+

或者你可以按照你的要求去做。

答案 1 :(得分:0)

<强>目标

  

为column3值添加双引号,并使用scala将column3值中的双引号替换为单引号。

我建议使用RegEx,因为你可以更灵活地使用它。

以下是解决方案:

val kafkaMsg = List("""{"column1":"abc","column2":"123","column3":qwe"r"ty,"column4":"abc123"}""", """{"column1":"defhj","column2":"45","column3":asd"f"gh,"column4":"def12d"}""", """{"column1":"defhj","column2":"45","column3":without-quotes,"column4":"def12d"}""")
val rdd = sc.parallelize(kafkaMsg)
val rePattern = """(^\{.*)("column3":)(.*)(,"column4":.*)""".r
val newRdd = rdd.map(r => 
    r match { 
        case rePattern(start, col3, col3Value, end) => (start + col3 + '"' + col3Value.replaceAll("\"", "'") + '"' + end)
        case _ => r }
    )

newRdd.foreach(println)

<强>解释

  1. 第一个和第二个语句是rdd初始化。

  2. 第三行定义正则表达式模式。您可能需要根据自己的情况进行调整。

    正则表达式产生4组值(a()中的任何值都是一组):

    • 以“{”开头的字符串以及在我们遇到“column3”之后的任何内容:
    • “column3”:本身
    • “column3”之后的任何内容:但之前,“column4”:
    • 无论什么开始,“column4”:

    我在下一个声明中使用这4组。

  3. 迭代你的rdd,对正则表达式运行它,并更改它:用单引号替换双引号,并添加打开/关闭引号。如果没有匹配,将返回原始字符串。

    因为regex是用4组定义的,所以我使用4个变量来映射匹配:

    case rePattern(start, col3, col3Value, end) =>
    

    注意:代码不会检查您是否在值中有双引号,它只是运行更新。如果需要,您可以自己添加验证。

  4. 显示结果。

  5. 重要说明: 我使用的正则表达式严格链接到您的源字符串格式。请记住,您有JSON,因此无法保证您的密钥顺序。因此,最终可能会出现“column4”(用作column3值结尾)可能会出现在“column3”之前。

    如果您使用逗号作为键/值结尾,请确保您没有将其作为column3值的一部分。

    底线:您需要调整我的正则表达式以正确识别column3值的结尾。

    希望它有所帮助。