Регулярные выражения Scala (строка, заключенная в двойные кавычки)

Я новичок в скале. Я пытаюсь сопоставить строку, заключенную в двойные кавычки, и меня немного озадачивает следующее поведение:

Если я сделаю следующее:

val stringRegex = """"([^"]*)"(.*$)"""
val regex = stringRegex.r
val tidyTokens = Array[String]("1", "\"test\"", "'c'", "-23.3")
tidyTokens.foreach {
    token => if (token.matches (stringRegex)) println (token + " matches!")
}

я получил

"test" matches!

в противном случае, если я сделаю следующее:

tidyTokens.foreach {
    token => token match {
        case regex(token) => println (token + " matches!")
        case _ => println ("No match for token " + token)
    }
}

я получил

No match for token 1
No match for token "test"
No match for token 'c'
No match for token -23.3

Почему «тест» не совпадает во втором случае?


person gbgnv    schedule 27.02.2013    source источник


Ответы (1)


Возьмите свое регулярное выражение:

 "([^"]*)"(.*$)

При компиляции с .r эта строка дает объект regex, который, если он соответствует входной строке, должен давать 2 захваченные строки — одну для ([^"]*), а другую для (.*$). Ваш код

  case regex(token) => ...

Должен отразить это, так что, может быть, вы хотите

  case regex(token, otherStuff) => ...

Или просто

  case regex(token, _) => ...

Почему? Поскольку синтаксис case regex(matchedCaputures...) работает, потому что regex — это объект с методом unapplySeq. case regex(token) => ... переводится (примерно) как:

 case List(token) => ...

Где List(token) — это то, что возвращает regex.unapplySeq( inputString ):

 regex.unapplySeq("\"test\"") // Returns Some(List("test", ""))

Ваше регулярное выражение соответствует строке "test", но в операторе case метод unapplySeq экстрактора регулярных выражений возвращает список из 2 строк, потому что это то, что регулярное выражение говорит, что оно захватывает. К сожалению, компилятор здесь вам не поможет, потому что регулярные выражения компилируются из строк во время выполнения.

Одной из альтернатив может быть использование группы без захвата:

 val stringRegex = """"([^"]*)"(?:.*$)"""
 //                             ^^

Тогда ваш код будет работать, потому что regex теперь будет объектом экстрактора, чей метод unapplySeq возвращает только одну захваченную группу:

 tidyTokens foreach { 
    case regex(token) => println (token + " matches!")
    case t => println ("No match for token " + t)
 }

Ознакомьтесь с руководством по Extractor Objects, чтобы лучше понять, как apply / unapply / unapplySeq работает.

person Faiz    schedule 27.02.2013
comment
Спасибо! Также для ссылки на объекты экстрактора! - person gbgnv; 27.02.2013