scala의 문자열과 연관된 패턴 매치에 대한 예시이다.
자바는 정규 표현식과 관련된 클래스가 Pattern, Matcher가 있지만, scala에서는 scala.util.matching.Regex 클래스가 존재한다. 패턴을 정의하고, 문자열에 대한 패턴 정보를 findAllIn 메소드(findXXX 시리즈로 다양한 제어를 할 수 있다)로 확인할 수 있다.
val pattern1 = new scala.util.matching.Regex("(H|h)ello")
val str = "Hello Mom, hello Dad"
println(pattern1.findAllIn(str).mkString(","))
결과는 다음과 같다.
Hello,hello
하지만, 꼭 scala.util.matching.Regex를 명시해서 사용할 필요는 없다. 정규 표현식으로 사용할 표현식에 .r을 붙이면 알아서 Regex 타입의 인스턴스가 생성된다.
val numPattern = "[0-9]+".r
// scala.util.matching.Regex = [0-9]+
val str1 = "Hello Mom 911, hello Dad 119?"
val matches = numPattern.findAllIn(str1)
println(matches.toList)
결과는 다음과 같다.
List(911, 119)
Regex의 findFirstIn을 사용하면 Option으로 리턴한다.
val numPattern = "[0-9]+".r val str1 = "Hello Mom 911, hello Dad 119?"
println(numPattern.findFirstIn(str1))
println(numPattern.findFirstIn(str))
결과는 다음과 같다.
Some(911)
None
Option의 특징을 활용해서 Some과 None에 대한 case 문을 작성할 수 있다.
numPattern.findFirstIn(str1) match {
case Some(s) => println(s)
case None => println("None")
}
numPattern.findFirstIn(str) match {
case Some(s) => println(s)
case None => println("None")
}
결과는 다음과 같다.
911
None
이번에는 반대로, 특정 문자열에 대해 regex 타입을 case 문에 넣을 수 있다. 그리고,
// string match
val sp = "[a-zA-Z]".r
val np = "xxx".r
"bus 1503, 5, 222" foreach {
case sp => println("s : " + sp)
case np => println("n : " + np)
}
결과는 다음과 같다.
s : b
s : u
s : s
s :
s : 1
s : 5
s : 0
s : 3
s : ,
s :
s : 5
s : ,
s :
s : 2
s : 2
s : 2
case 문이나 find 메소드 없이 아주 간단하게 정규 표현식을 읽을 수 있다.
val regex = "(\\d+)/(\\d+)/(\\d+)".r
val regex(year, month, day) = "2016/11/01"
println(year, month, day)
결과는 다음과 같다.
(2016,11,01)
그리고, 정확치 않은 정규 표현식이라면, 적당히 알아서 나온다(뒤에서 부터 파싱되었다).
val regex1 = """(\d+)(\d+)(\d+)""".r
val regex1(a, b, c) = "112801"
println(a, b, c)
결과는 다음과 같다.
(1128,0,1)
간단한 문자열도 이와 같이 실행할 수 있다.
val Name = """(\w+)\s+(\w+)""".r
val Name(firstName, lastName) = "samuel kim"
println(firstName, lastName)
"samuel kim" match {
case Name(first, last) => println(first, last)
case _ => println("x")
}
위 두 결과는 모두 다음과 같다.
(samuel,kim)
(samuel,kim)
이젠 full name도 쉽게 할 수 있다.
val FullName = """(\w+)\s+(\w+)\s+(\w+)""".r
val FullName(first, middle, last) = "samuel jackson kim"
println(first, middle, last)
결과는 다음과 같다.
(samuel,jackson,kim)
시간, 분, 초를 한번에 로그에 남겼을 경우 이를 예쁘게 보여줄 수 있는 함수이다.
val pattern = """([0-9]{1,2})([0-9]{1,2})([0-9]{1,2})""".r
val allMatches = pattern.findAllMatchIn("112801")
allMatches.foreach { m =>
println(m.group(1) + ":" + m.group(2) + ":" + m.group(3))
}
결과는 다음과 같다.
11:28:01
이를 Spark-Zeppelin으로 간단하게 보여주기 위해 getTime이라는 메소드를 만들었다.
val reqLog = textFile.filter(line=>line.contains("12314")).map(s=>s.split("\t")).map(
s=>RequestLog(getTime(s(1).toString),
s(5),
s(11),
s(21)
))
하나는 Regex에 findAllMatchIn과 foreach, group을 사용한 함수와
또 다른 하나는 Regex에 findAllIn과 case를 이용한 방식을 사용했다.
def getTime(time: String): String = {
val pattern = """([0-9]{1,2})([0-9]{1,2})([0-9]{1,2})([0-9]{1,5})""".r
val allMatches = pattern.findAllMatchIn(time)
var result = ""
allMatches.foreach { m =>
result = m.group(1) + ":" + m.group(2) + ":" + m.group(3) + "." + m.group(4)
}
result
}
def getTime2(time: String): String = {
val pattern = """([0-9]{1,2})([0-9]{1,2})([0-9]{1,2})([0-9]{1,5})""".r
var result = ""
pattern.findAllIn(time) foreach {
case pattern(hour, minute, second, millisecond) => result = hour + ":" + minute + ":" + second + "." + millisecond
}
result
}
println(getTime("1128000000"))
println(getTime2("1128000000"))
결과는 다음과 같다.
11:28:00.0000
11:28:00.0000
'scala' 카테고리의 다른 글
[scala] 암시 증거 (implicit evidence) (0) | 2016.11.03 |
---|---|
[scala] 암시 implicitly (0) | 2016.11.03 |
[scala] 참조 투명성(referential transparency)과 부작용(side effect) (0) | 2016.10.31 |
[scala] 다른 라이브러리를 포함시킬 수 있는 REPL 환경 (0) | 2016.10.31 |
[scala] Array, WrappedArray (0) | 2016.10.29 |