단어의 첫 글자와 “ABC”와 같은 그룹의 글자 중 하나가 일치하는 항목을 찾고 싶습니다. 의사 코드에서 이것은 다음과 같이 보일 수 있습니다.
case Process(word) =>
word.firstLetter match {
case([a-c][A-C]) =>
case _ =>
}
}
하지만 Java 대신 Scala에서 첫 글자를 잡는 방법은 무엇입니까? 정규식을 올바르게 표현하려면 어떻게해야합니까? 케이스 클래스 내에서이 작업을 수행 할 수 있습니까?
답변
정규식이 추출기를 정의하기 때문에이를 수행 할 수 있지만 먼저 정규식 패턴을 정의해야합니다. 나는 이것을 테스트하기 위해 Scala REPL에 액세스 할 수 없지만 이와 같은 것이 작동합니다.
val Pattern = "([a-cA-C])".r
word.firstLetter match {
case Pattern(c) => c bound to capture group here
case _ =>
}
답변
버전 2.10부터 Scala의 문자열 보간 기능을 사용할 수 있습니다.
implicit class RegexOps(sc: StringContext) {
def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
}
scala> "123" match { case r"\d+" => true case _ => false }
res34: Boolean = true
더 좋은 방법은 정규식 그룹을 바인딩 할 수 있습니다.
scala> "123" match { case r"(\d+)$d" => d.toInt case _ => 0 }
res36: Int = 123
scala> "10+15" match { case r"(\d\d)${first}\+(\d\d)${second}" => first.toInt+second.toInt case _ => 0 }
res38: Int = 25
더 자세한 바인딩 메커니즘을 설정할 수도 있습니다.
scala> object Doubler { def unapply(s: String) = Some(s.toInt*2) }
defined module Doubler
scala> "10" match { case r"(\d\d)${Doubler(d)}" => d case _ => 0 }
res40: Int = 20
scala> object isPositive { def unapply(s: String) = s.toInt >= 0 }
defined module isPositive
scala> "10" match { case r"(\d\d)${d @ isPositive()}" => d.toInt case _ => 0 }
res56: Int = 10
무엇을 사용할 수 있는지에 대한 인상적인 예 Dynamic
는 블로그 게시물 Introduction to Type Dynamic에서 볼 수 있습니다 .
object T {
class RegexpExtractor(params: List[String]) {
def unapplySeq(str: String) =
params.headOption flatMap (_.r unapplySeq str)
}
class StartsWithExtractor(params: List[String]) {
def unapply(str: String) =
params.headOption filter (str startsWith _) map (_ => str)
}
class MapExtractor(keys: List[String]) {
def unapplySeq[T](map: Map[String, T]) =
Some(keys.map(map get _))
}
import scala.language.dynamics
class ExtractorParams(params: List[String]) extends Dynamic {
val Map = new MapExtractor(params)
val StartsWith = new StartsWithExtractor(params)
val Regexp = new RegexpExtractor(params)
def selectDynamic(name: String) =
new ExtractorParams(params :+ name)
}
object p extends ExtractorParams(Nil)
Map("firstName" -> "John", "lastName" -> "Doe") match {
case p.firstName.lastName.Map(
Some(p.Jo.StartsWith(fn)),
Some(p.`.*(\\w)$`.Regexp(lastChar))) =>
println(s"Match! $fn ...$lastChar")
case _ => println("nope")
}
}
답변
delnan이 지적했듯이 match
Scala 의 키워드는 정규식 과 관련이 없습니다. 문자열이 정규식과 일치하는지 확인하려면 String.matches
메서드를 사용할 수 있습니다 . 문자열이 소문자 또는 대문자로 a, b 또는 c로 시작하는지 확인하려면 정규식은 다음과 같습니다.
word.matches("[a-cA-C].*")
이 정규식은 “문자 a, b, c, A, B 또는 C 중 하나 다음에 아무 것이나 오는 것”으로 읽을 수 있습니다 ( .
“모든 문자”를 *
의미하고 “0 회 이상 “을 의미하므로 “. *”는 모든 문자열). .
답변
Andrew의 대답을 조금 확장하려면 : 정규식이 추출기를 정의한다는 사실은 Scala의 패턴 일치를 사용하여 정규식과 일치하는 하위 문자열을 매우 잘 분해하는 데 사용할 수 있습니다.
val Process = """([a-cA-C])([^\s]+)""".r // define first, rest is non-space
for (p <- Process findAllIn "aha bah Cah dah") p match {
case Process("b", _) => println("first: 'a', some rest")
case Process(_, rest) => println("some first, rest: " + rest)
// etc.
}
답변
String.matches는 정규식 의미에서 패턴 일치를 수행하는 방법입니다.
하지만, 실제 Scala 코드의 word.firstLetter는 다음과 같습니다.
word(0)
Scala는 Strings를 Char의 시퀀스로 취급하므로 어떤 이유로 든 String의 첫 번째 문자를 명시 적으로 가져와 일치 시키려면 다음과 같이 사용할 수 있습니다.
"Cat"(0).toString.matches("[a-cA-C]")
res10: Boolean = true
정규식 패턴 일치를 수행하는 일반적인 방법으로 이것을 제안하지는 않지만 먼저 String의 첫 번째 문자를 찾은 다음 정규식과 일치시키는 제안 된 접근 방식과 일치합니다.
편집 : 명확하게 말하면 다른 사람들이 말했듯이 이것을하는 방법은 다음과 같습니다.
"Cat".matches("^[a-cA-C].*")
res14: Boolean = true
가능한 한 초기 의사 코드에 가까운 예제를 보여주고 싶었습니다. 건배!
답변
@AndrewMyers의 답변의 접근 방식은 전체 문자열을 정규식 과 일치시키고 ^
및을 사용하여 문자열의 양쪽 끝에 정규식을 고정하는 효과가 $
있습니다. 예:
scala> val MY_RE = "(foo|bar).*".r
MY_RE: scala.util.matching.Regex = (foo|bar).*
scala> val result = "foo123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = foo
scala> val result = "baz123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = No match
scala> val result = "abcfoo123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = No match
그리고 .*
끝 이 없습니다 .
scala> val MY_RE2 = "(foo|bar)".r
MY_RE2: scala.util.matching.Regex = (foo|bar)
scala> val result = "foo123" match { case MY_RE2(m) => m; case _ => "No match" }
result: String = No match
답변
먼저 정규 표현식을 별도로 사용할 수 있음을 알아야합니다. 다음은 그 예입니다.
import scala.util.matching.Regex
val pattern = "Scala".r // <=> val pattern = new Regex("Scala")
val str = "Scala is very cool"
val result = pattern findFirstIn str
result match {
case Some(v) => println(v)
case _ =>
} // output: Scala
둘째, 정규 표현식과 패턴 매칭을 결합하는 것이 매우 강력하다는 것을 알아야합니다. 다음은 간단한 예입니다.
val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
"2014-11-20" match {
case date(year, month, day) => "hello"
} // output: hello
사실 정규 표현식 자체는 이미 매우 강력합니다. 우리가해야 할 유일한 일은 Scala로 더 강력하게 만드는 것입니다. 다음은 Scala 문서의 더 많은 예제입니다. http://www.scala-lang.org/files/archive/api/current/index.html#scala.util.matching.Regex