预先将正则表达式模式附加到拆分并将案例类映射到拆分
Posted
技术标签:
【中文标题】预先将正则表达式模式附加到拆分并将案例类映射到拆分【英文标题】:Pre append regex pattern to split and map case class to splitted 【发布时间】:2018-11-11 11:50:17 【问题描述】:我想拆分以下格式为
的字符串val str = "X|blnk_1|blnk_2|blnk_3|blnk_4|time1|time2|blnk_5|blnk_6|blnk_7|blnk_8| |Z01|Str1|01|001|NE]|[HEX1|HEX2]|[NA|001:1000|123:456|[00]|]|Z01|Str2|02|002|NE]|[HEX3|HEX4]|[NA|002:1001|234:456|[01]|]|Z02|02|z2|Str|Str|"
这个字符串总是以 X 开头,分割位置是 Z01,Z02,...,Z0D
str.split("""\|Z0[1|2|3|4|5|6|7|8|9|A|B|C|D]1\|""") foreach println
这里Z01,...,Z0D的位置不可能出现在字符串中。
拆分给出了预期的结果:
X|blnk_1|blnk_2|blnk_3|blnk_4|time1|time2|blnk_5|blnk_6|blnk_7|blnk_8|
Str1|01|001|NE]|[HEX1|HEX2]|[NA|001:1000|123:456|[00]|]
Str2|02|002|NE]|[HEX3|HEX4]|[NA|002:1001|234:456|[01]|]
02|z2|Str|Str|
但是,我想将 X、Z01、... 映射到案例类。由于没有排序,因此无法确定需要映射到哪个案例类拆分(不能使用单个拆分的长度)。
我希望我的拆分有以下输出:
X|blnk_1|blnk_2|blnk_3|blnk_4|time1|time2|blnk_5|blnk_6|blnk_7|blnk_8|
Z01|[Str1|01|001|NE]|[HEX1|HEX2]|[NA|001:1000|123:456|[00]|]|
Z01|[Str2|02|002|NE]|[HEX3|HEX4]|[NA|002:1001|234:456|[01]|]|
Z01|02|z2|Str|Str|
这样结果可以在预先附加的模式的帮助下映射到案例类。
例如:
case class X( ....)
case class Z01(val1: String, val2: String, val3: String)
case class Z02(val1: Int, val2: String, val3: String,val4:String)
.................
X|blnk_1|blnk_2|blnk_3|blnk_4|time1|time2|blnk_5|blnk_6|blnk_7|blnk_8|
映射到 case class X
和
Z01|[Str1|01|001|NE]|[HEX1|HEX2]|[NA|001:1000|123:456|[00]|]|
映射到案例类 Z01
最终结果应该是有序和相似的组的形式,被视为特定案例类的数组。
X
Array[Z01]
Array[Z02]
......
......
【问题讨论】:
看起来简单的str.split("Z")
然后手动解析呢?
@Jatin 这实际上是 Spark 数据帧转换的一部分。我想一次性完成。
我无法确认。但它可能会消耗更少的时钟周期。正则表达式是一个连续的时间杀手。按单个字符拆分不会在内部调用正则表达式,而是简单的字符串迭代
【参考方案1】:
这个想法怎么样?
val x = str.split("""\|Z0[1|2|3|4|5|6|7|8|9|A|B|C|D]1\|""") // actual string splits
val y = """\|Z0[1|2|3|4|5|6|7|8|9|A|B|C|D]1\|""".r.findAllIn(str).toArray // delimiters Array
val final_data = x.slice(1, x.size).zip(y).map(x => x._2+x._1).toList // taking actual splits except first one .... and then zipping and concatenating with delimiters like below.
/*
List(|Z01|Str1|01|001|NE]|[HEX1|HEX2]|[NA|001:1000|123:456|[00]|], |Z01|Str2|02|002|NE]|[HEX3|HEX4]|[NA|002:1001|234:456|[01]|], |Z02|02|z2|Str|Str|) */
final_data 中的第一个|
可以用subString
删除
【讨论】:
【参考方案2】:作为替代方案,它可能是通过匹配它们来获取您的值的一种选择:
(?:Z0[1-9A-D]|^X).*?(?=\|Z0[1-9A-D]|$)
这匹配:
(?:Z0[1-9A-D]|X\|)
在非捕获组中匹配 Z0
并在字符类中列出可能的选项或 |
X 在行的开头 ^
.*?
匹配任意字符一次或多次非贪心
(?=\|Z0[1-9A-D]|$)
肯定的前瞻,它断言后面是一个管道 |
后跟 Z0
和字符列表中的一个字符或 |
行尾 $
例如:
val re = """(?:Z0[1-9A-D]|^X).*?(?=\|Z0[1-9A-D]|$)""".r
val str = "X|blnk_1|blnk_2|blnk_3|blnk_4|time1|time2|blnk_5|blnk_6|blnk_7|blnk_8| |Z01|Str1|01|001|NE]|[HEX1|HEX2]|[NA|001:1000|123:456|[00]|]|Z01|Str2|02|002|NE]|[HEX3|HEX4]|[NA|002:1001|234:456|[01]|]|Z02|02|z2|Str|Str|"
re.findAllIn(str) foreach println
这将导致:
X|blnk_1|blnk_2|blnk_3|blnk_4|time1|time2|blnk_5|blnk_6|blnk_7|blnk_8|
Z01|Str1|01|001|NE]|[HEX1|HEX2]|[NA|001:1000|123:456|[00]|]
Z01|Str2|02|002|NE]|[HEX3|HEX4]|[NA|002:1001|234:456|[01]|]
Z02|02|z2|Str|Str|
Demo
【讨论】:
以上是关于预先将正则表达式模式附加到拆分并将案例类映射到拆分的主要内容,如果未能解决你的问题,请参考以下文章