Как заменить часть строки с помощью сопоставления с регулярным выражением в Scala? - PullRequest
0 голосов
/ 09 февраля 2019

У меня есть строка, которая содержит имена столбцов и типы данных, как показано ниже:

val cdt = "header:integer|releaseNumber:numeric|amountCredit:numeric|lastUpdatedBy:numeric(15,10)|orderNumber:numeric(20,0)"

Мое требование заключается в преобразовании типов данных postgres, представленных как numeric, numeric(15,10), в типы данных, совместимые с spark-sql.В этом случае

numeric         -> decimal(38,30)
numeric(15,10)  -> decimal(15,10)
numeric(20,0)   -> bigint   (This is an integeral datatype as there its precision is zero.)

Чтобы получить доступ к типу данных в строке: cdt, я разделил его и создал из него Seq.

val dt = cdt.split("\\|").toSeq

Теперь у меня есть Seq ofэлементы, в которых каждый элемент является строкой в ​​следующем формате:

Seq("header:integer", "releaseNumber:numeric","amountCredit:numeric","lastUpdatedBy:numeric(15,10)","orderNumber:numeric(20,0)")

У меня есть регулярное выражение для сопоставления с образцом: """numeric\(\d+,(\d+)\)""".r, для числового (точность, масштаб), которое работает только при наличии масштаба двухцифры, например: числовые (20,23).Я очень плохо знаком с REGEX и Scala, и я не понимаю, как создать паттерны регулярных выражений для оставшихся двух случаев и применить их к строке, чтобы соответствовать условию.Я попытался сделать это следующим образом, но он выдает ошибку компиляции: «Не удается разрешить символ findFirstMatchIn»

dt.map(e => e.split("\\:")).map(e => changeDataType(e(0), e(1)))
 def changeDataType(colName: String, cd:String): String = {
    val finalColumns = new String
    val pattern1 = """numeric\(\d+,(\d+)\)""".r
    cd match {
      case pattern1.findFirstMatchIn(dt) =>
    }
  }

Я пытаюсь получить окончательный вывод в строку, как показано ниже:

header:integer|releaseNumber:decimal(38,30)|amountCredit:decimal(38,30)|lastUpdatedBy:decimal(15,10)|orderNumber:bigint

Как создать несколько шаблонов регулярных выражений для разных случаев, чтобы проверить / применить сопоставление шаблонов для типа данных каждого значения в seq и изменить его на мой подходящий тип данных, как упомянуто выше.

Может кто-нибудь сообщить мне, как я могудостичь этого?

1 Ответ

0 голосов
/ 09 февраля 2019

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

val numericRE = raw"([^:]+):numeric(?:\((\d+),(\d+)\))?".r

cdt.split("\\|")
   .map{
     case numericRE(col,a,b) =>
       if (Option(b).isEmpty) s"$col:decimal(38,30)"
       else if (b == "0")     s"$col:bigint"
       else                   s"$col:decimal($a,$b)"
     case x => x  //pass-through
  }.mkString("|")

//res0: String = header:integer|releaseNumber:decimal(38,30)|amountCredit:decimal(38,30)|lastUpdatedBy:decimal(15,10)|orderNumber:bigint

Конечно, это может быть сделано с тремя различными шаблонами регулярных выражений, но я думаю, что это довольноочистить.


объяснение

  • raw - не нужно так много escape-символов - \
  • ([^:]+) - захватить все до 1-го двоеточия
  • :numeric - за ним следует строка ": numeric"
  • (?: - начать группу без захвата
  • \((\d+),(\d+)\) - захватить 2-значные строки, разделенные запятой, внутри скобок
  • )? - необязательная группа необязательна
  • numericRE(col,a,b) - col - 1-йгруппа захвата, a и b - это захваты цифр, но они находятся внутри необязательной группы без захвата, поэтому они могут быть null
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...