Хороший способ получить доступ к результатам матчей? - PullRequest
0 голосов
/ 18 сентября 2018

Мое требование - преобразовать некоторые идентификаторы текстовых сообщений.Ввод:

a.messageid=X0001E
b.messageid=Y0001E

Задача состоит в том, чтобы превратить это в

a.messageid=Z00001E
b.messageid=Z00002E

Другими словами: получить первую часть каждой строки (например: a.) и добавить немного разныеid.

Мое текущее решение:

val matcherForIds = Regex("(.*)\\.messageid=(X|Y)\\d{4,6}E")  
var idCounter = 5

fun transformIds(line: String): String {
    val result = matcherForIds.matchEntire(line) ?: return line
    return "${result.groupValues.get(1)}.messageid=Z%05dE".format(messageCounter++)
}

Это работает , но найти способ, которым я получаю первый матч "${result.groupValues.get(1)}, не очень элегантно.

Есть ли более удобный для чтения / более краткий способ доступа к первому совпадению?

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Может быть, не совсем то, что вы ищете, но, возможно, это так.Что, если вы сначала обеспечите (отфильтруете) интересующие линии и просто замените то, что нужно заменить, например, используйте следующую функцию преобразования:

val matcherForIds = Regex("(.*)\\.messageid=(X|Y)\\d{4,6}E")
val idRegex = Regex("[XY]\\d{4,6}E")
var idCounter = 5

fun transformIds(line: String) = idRegex.replace(line) {
  "Z%05dE".format(idCounter++)
}

со следующим фильтром:

"a.messageid=X0001E\nb.messageid=Y0001E"
  .lineSequence()
  .filter(matcherForIds::matches)
  .map(::transformIds)
  .forEach(::println)

В случае, если есть и другие релевантные строки, которые вы хотите сохранить, тогда возможно следующее, но не такое приятное, как решение в конце:

"a.messageid=X0001E\nnot interested line, but required in the output!\nb.messageid=Y0001E"
  .lineSequence()
  .map {
    when {
      matcherForIds.matches(it) -> transformIds(it)
      else -> it
    }
  }
  .forEach(::println)

В качестве альтернативы (теперь просто копируем регулярное выражение Wiktors, поскольку он уже содержит все, что нам нужно (полное соответствие от начала строки ^ до конца строки $ и т. д.)):

val matcherForIds = Regex("""^(.*\.messageid=)[XY]\d{4,6}E$""")
fun transformIds(line: String) = matcherForIds.replace(line) {
  "${it.groupValues[1]}Z%05dE".format(idCounter++)
}

Таким образом, вы гарантируете, что строки, которые полностью соответствуюттребуемые входные данные заменяются, а остальные сохраняются, но не заменяются.

0 голосов
/ 18 сентября 2018

Вы можете получить результат без отдельной функции:

val line = s.replace("""^(.*\.messageid=)[XY]\d{4,6}E$""".toRegex()) { 
    "${it.groupValues[1]}Z%05dE".format(messageCounter++) 
}

Однако, поскольку вам нужно format messageCounter в результате, вы не можете просто использовать шаблон замены строки и не можетеизбавиться от ${it.groupValues[1]}.

Также обратите внимание:

  • Вы можете избавиться от двойных обратных косых черт с помощью строкового литерала в тройных кавычках
  • Существуетнет необходимости добавлять .messageid= к замене, если вы записываете эту часть в группу 1 (см. (.*\.messageid=))
  • Нет необходимости захватывать X или Y, так как вы не используете их позже, таким образом, (X|Y) можно заменить на более эффективный класс символов [XY].
  • . ^ и $ гарантируют, что шаблон должен соответствовать всей строке, иначе совпадение не будет иСтрока будет возвращена как есть, без каких-либо изменений.

См. демо Kotlin онлайн .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...