Как сопоставить шаблон с использованием регулярного выражения в Scala?
Я хотел бы найти совпадение между первой буквой слова и одной из букв в группе, такой как "ABC". В псевдокоде это может выглядеть примерно так:
case Process(word) =>
word.firstLetter match {
case([a-c][A-C]) =>
case _ =>
}
}
Но как я могу взять первую букву в Scala вместо Java? Как правильно выразить регулярное выражение? Возможно ли это сделать в классе case?
Ответы
Ответ 1
Вы можете сделать это, потому что регулярные выражения определяют экстракторы, но сначала вам нужно определить шаблон регулярного выражения. У меня нет доступа к Scala REPL, чтобы проверить это, но что-то вроде этого должно работать.
val Pattern = "([a-cA-C])".r
word.firstLetter match {
case Pattern(c) => c bound to capture group here
case _ =>
}
Ответ 2
Начиная со версии 2.10, можно использовать функцию интерполяции строк Scala:
implicit class Regex(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
, показан в сообщении блога Введение в динамический тип:
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")
}
}
Ответ 3
Как отметил Делнан, ключевое слово match
в Scala не имеет ничего общего с регулярными выражениями. Чтобы узнать, соответствует ли строка регулярному выражению, вы можете использовать метод String.matches
. Чтобы узнать, начинается ли строка с a, b или c в нижнем или верхнем регистре, регулярное выражение будет выглядеть так:
word.matches("[a-cA-C].*")
Вы можете прочитать это регулярное выражение как "один из символов a, b, c, A, B или C, за которым следует что-либо" (.
означает "любой символ" и *
означает "ноль или более раз", поэтому ". *" - любая строка).
Ответ 4
Чтобы немного рассказать о Andrew answer: факт, что регулярные выражения определяют экстракторы, можно использовать для декомпозиции подстрок, соответствующих регулярному выражению, очень хорошо, используя шаблон 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.
}
Ответ 5
Обратите внимание, что подход от ответа @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
Ответ 6
String.matches - это способ сопоставления шаблонов в смысле регулярного выражения.
Но, как удобно, word.firstLetter в реальном коде Scala выглядит следующим образом:
word(0)
Scala рассматривает строки как последовательность Char, поэтому, если по какой-то причине вы хотели явно получить первый символ строки и сопоставить ее, вы можете использовать что-то вроде этого:
"Cat"(0).toString.matches("[a-cA-C]")
res10: Boolean = true
Я не предлагаю это как общий способ сопоставления шаблонов регулярных выражений, но он соответствует предложенному подходу, чтобы сначала найти первый символ строки и затем сопоставить его с регулярным выражением.
EDIT:
Чтобы быть ясным, то, как я это сделал, будет, как говорили другие:
"Cat".matches("^[a-cA-C].*")
res14: Boolean = true
Просто хотел показать пример как можно ближе к исходному псевдокоду. Ура!
Ответ 7
Сначала мы должны знать, что регулярное выражение может использоваться отдельно. Вот пример:
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