Как извлечь часть строки, которая не соответствует шаблону - PullRequest
1 голос
/ 26 марта 2019

Я хочу извлечь часть строки, которая не соответствует шаблону

Мое условие сопоставления с образцом - это sting, должен иметь длину 5 и содержать только N или Y.

Пример:

NYYYY => valid

NY    => Invalid , length is invalid

NYYSY => Invalid. character at position 3 is invalid

Если строка недопустима, я хочу выяснить, какой именно символ не соответствует. Пример: в NYYSY 4-й персонаж не совпадает.

Я пытался с сопоставлением с шаблоном в Scala

val Pattern = "([NY]{5})".r
    paramList match {
     case Pattern(c) => true
     case _  => false
    }

Ответы [ 5 ]

2 голосов
/ 26 марта 2019

Возвращает String, указывающий статус проверки.

def validate(str :String, len :Int, cs :Seq[Char]) :String = {
  val checkC = cs.toSet
  val errs = str.zipAll(Range(0,len), 1.toChar, -1).flatMap{ case (c,x) =>
               if      (x < 0)     Some("too long")
               else if (checkC(c)) None
               else if (c == 1)    Some("too short")
               else                Some(s"'$c' at index $x")
             }
  str + ": " + (if (errs.isEmpty) "valid" else errs.distinct.mkString(", "))
}

проверка:

validate("NTYYYNN", 4, "NY")  //res0: String = NTYYYNN: 'T' at index 1, too long
validate("NYC",     7, "NY")  //res1: String = NYC: 'C' at index 2, too short
validate("YNYNY",   5, "NY")  //res2: String = YNYNY: valid
1 голос
/ 26 марта 2019

Вот один подход, который возвращает список (Char, Int) кортежей недопустимых символов и их соответствующих позиций в данной строке:

def checkString(validChars: List[Char], validLength: Int, s: String) = {
  val Pattern = s"([${validChars.mkString}]{$validLength})".r

  s match {
    case Pattern(_) => Vector.empty[(Char, Int)]
    case s =>
      val invalidList = s.zipWithIndex.filter{case (c, _) => !validChars.contains(c)}
      if (invalidList.nonEmpty) invalidList else Vector(('\u0000', -1))
  }
}

List("NYYYY", "NY", "NNSYYTN").map(checkString(List('N', 'Y'), 5, _))
// res1: List(Vector(), Vector((?,-1)), Vector((S,2), (T,5)))

Как показано выше, список empty представляет допустимую строку исписок (null-char, -1) означает, что строка содержит допустимые символы, но недопустимую длину.

0 голосов
/ 26 марта 2019

Этого можно добиться с помощью сопоставления шаблонов с каждым символом строки без использования каких-либо регулярных выражений или сложных манипуляций со строками.

def check(value: String): Unit = {
  if(value.length!=5) println(s"$value length is invalid.")
  else value.foldLeft((0, Seq[String]())){
    case (r, char) =>
      char match {
        case 'Y' | 'N' => r._1+1 -> r._2
        case c @ _ => r._1+1 -> {r._2 ++ List(s"Invalid character `$c` in position ${r._1}")}
      }
  }._2 match {
    case Nil => println(s"$value is valid.")
    case errors: List[String] => println(s"$value is invalid - [${errors.mkString(", ")}]")
  }
}

check("NYCNBNY")
NYNYNCC length is invalid.

check("NYCNB")
NYCNB is invalid - [Invalid character `C` in position 2, Invalid character `B` in position 4]

check("NYNNY")
NYNNY is valid.
0 голосов
/ 26 марта 2019

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

val Pattern = "([NY]{5})".r
val TooLong = "([NY]{5})(.+)".r
val WrongChar = "([NY]*)([^NY].*)".r

paramList match {
  case Pattern(c) => // Good
  case TooLong(head, rest) => // Extra character(s) in sequence
  case WrongChar(head, rest) => // Wrong character in sequence
  case _ => // Too short
}

Вы можете определить индекс ошибки, используя head.length, а ошибочный символ - rest.head.

0 голосов
/ 26 марта 2019

Вот одно предложение, которое может удовлетворить ваши потребности:

"NYYSY".split("(?<=[^NY])|(?=[^NY])").foreach(println) 

NYY
S
Y

Это решение разбивает входную строку в любой точке, когда предыдущий или следующий символ равен , а не a Yили N.Это помещает каждый остров действительных и недопустимых символов в отдельные строки в выводе.

...