我有一个包含以下列名称和数据类型的字符串:
val cdt = "header:integer|releaseNumber:numeric|amountCredit:numeric|lastUpdatedBy:numeric(15,10)|orderNumber:numeric(20,0)"
我的要求是将以numeric, numeric(15,10)
形式存在的postgres数据类型转换为spark-sql兼容的数据类型。
在这种情况下,
numeric -> decimal(38,30)
numeric(15,10) -> decimal(15,10)
numeric(20,0) -> bigint (This is an integeral datatype as there its precision is zero.)
为了访问字符串cdt中的数据类型,我将其拆分并由此创建了一个Seq。
val dt = cdt.split("\\|").toSeq
现在我有一个元素序列,其中每个元素都是以下格式的字符串:
Seq("header:integer", "releaseNumber:numeric","amountCredit:numeric","lastUpdatedBy:numeric(15,10)","orderNumber:numeric(20,0)")
我有与模式匹配的正则表达式:"""numeric\(\d+,(\d+)\)""".r
,用于数字(精度,小数位数),仅当存在
两位数的小数位数,例如:numeric(20,23)。
我是REGEX和Scala的新手,我不了解如何为其余两种情况创建regex模式,并将其应用于字符串以匹配条件。我以下面的方式尝试了它,但它给了我一个编译错误:“无法解析符号findFirstMatchIn”
dt.map(e => e.split("\\:")).map(e => changeDataType(e(0), e(1)))
def changeDataType(colName: String, cd:String): String = {
val finalColumns = new String
val pattern1 = """numeric\(\d+,(\d+)\)""".r
cd match {
case pattern1.findFirstMatchIn(dt) =>
}
}
我正在尝试将最终输出转换为字符串,如下所示:
header:integer|releaseNumber:decimal(38,30)|amountCredit:decimal(38,30)|lastUpdatedBy:decimal(15,10)|orderNumber:bigint
如何在不同情况下使用多个正则表达式模式来检查/对seq中每个值的数据类型应用模式匹配并将其更改为如上所述的我合适的数据类型。
任何人都可以让我知道如何实现吗?
答案 0 :(得分:3)
可以使用单个正则表达式模式完成此操作,但是需要对匹配结果进行一些测试。
val numericRE = raw"([^:]+):numeric(?:\((\d+),(\d+)\))?".r
cdt.split("\\|")
.map{
case numericRE(col,a,b) =>
if (Option(b).isEmpty) s"$col:decimal(38,30)"
else if (b == "0") s"$col:bigint"
else s"$col:decimal($a,$b)"
case x => x //pass-through
}.mkString("|")
//res0: String = header:integer|releaseNumber:decimal(38,30)|amountCredit:decimal(38,30)|lastUpdatedBy:decimal(15,10)|orderNumber:bigint
当然可以使用三种不同的正则表达式模式来完成,但是我认为这很清楚。
说明
raw
-不需要那么多转义字符-\
([^:]+)
-捕获第一个冒号之前的所有内容:numeric
-后跟字符串“:numeric” (?:
-创建一个非捕获组\((\d+),(\d+)\)
-在括号内捕获用逗号分隔的两位数字字符串)?
-非捕获组是可选的numericRE(col,a,b)
-col
是第一个捕获组,a
和b
是数字捕获,但是它们位于可选的非捕获组内,因此它们可能是null