我有很多带文本限定符的分隔文件(每列开头和结尾都有双引号)。定界不一致,即可以有任何分隔,如逗号(,),管道(|),〜,制表符(\ t)。
我需要用文本(单列)读取此文件,然后通过考虑文本限定符来检查分隔符的数量。如果任何记录的列数少于或多于列,则应拒绝该记录并将其加载到不同的路径。
下面是3列ID,名称和DESC的测试数据。 DESC列有额外的分隔符。
" ID""名称"" DESC"
" 1" ," ABC"," A,B C"
" 2" ," XYZ" ," ABC很烦恼"
" 3" ," YYZ" ,""
4," XAA" ," sf,sd
sdfsf"
由于desc字段中的新行字符
,最后一条记录被拆分为两条记录以下是我试图处理但无法正确处理的代码。
val SourceFileDF = spark.read.text(InputFilePath)
SourceFile = SourceFile.filter("value != ''") // Removing empty records while reading
val aCnt = coalesce(length(regexp_replace($"value","[^,]", "")), lit(0)) //to count no of delimiters
val Delimitercount = SourceFileDF.withColumn("a_cnt", aCnt)
var invalidrecords= Delimitercount
.filter(col("a_cnt")
.!==(NoOfDelimiters)).toDF()
val GoodRecordsDF = Delimitercount
.filter(col("a_cnt")
.equalTo(NoOfDelimiters)).drop("a_cnt")
使用上面的代码,我可以拒绝所有分隔符较少或更多的记录,但如果分隔符与文本限定符一起使用则无法忽略。
先谢谢。
答案 0 :(得分:1)
您可以使用replaceAllIn
的闭包来删除匹配中所需的任何字符:
var y = """4 , "XAA" , "sf,sd\nsdfsf""""
val pattern = """"[^"]*(?:""[^"]*)*"""".r
y = pattern replaceAllIn (y, m => m.group(0).replaceAll("[,\n]", ""))
print(y) // => 4 , "XAA" , "sfsdnsdfsf"
请参阅Scala demo。
<强>详情
"
- 匹配"
[^"]*
- 除"
(?:""[^"]*)*
- 匹配""
的0个或更多序列,然后匹配"
以外的0个字符"
- "
。代码在y
中查找上述模式的所有非重叠匹配,并在找到匹配项(m
)后,从匹配值中删除,
和换行符(LF) (使用m.group(0).replaceAll("[,\n]", "")
,其中m.group(0)
是匹配值,[,\n]
匹配,
或换行符。