From 393ba8d8cb8111cca65fabb2a277e35ddd43e81c Mon Sep 17 00:00:00 2001 From: airatmeister Date: Tue, 20 Dec 2022 16:14:37 +0300 Subject: [PATCH] INTERNAL-377: Placeholder generation from regex source expression --- .../roboswag/textprocessing/Constants.kt | 9 -- .../roboswag/textprocessing/TextFormatter.kt | 2 +- .../generators/DecoroMaskGenerator.kt | 4 +- .../generators/PlaceHolderGenerator.kt | 91 +++---------- .../regexgenerator/PCREGeneratorItem.kt | 2 +- .../regexgenerator/PCREGeneratorListener.kt | 57 ++++++--- .../PCREGeneratorListenerExt.kt | 121 ------------------ .../validators/CustomValidator.kt | 4 +- 8 files changed, 63 insertions(+), 227 deletions(-) delete mode 100644 text-processing/src/main/java/ru/touchin/roboswag/textprocessing/Constants.kt delete mode 100644 text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListenerExt.kt diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/Constants.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/Constants.kt deleted file mode 100644 index 49377d8..0000000 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/Constants.kt +++ /dev/null @@ -1,9 +0,0 @@ -package ru.touchin.roboswag.textprocessing - -object Constants { - internal const val digits = "1234567890" - internal const val charsRuUpper = "АБВГДЕЖЗИЙКЛМНОПРСТУФЧЦЧЭЮЯЪЬЫШ" - internal const val charsEngUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - internal const val charsRuLower = "абвгдежзийклмнопрстуфчцэюяъьыш" - internal const val charsEngLower = "abcdefghijklmnopqrstuvwxyz" -} \ No newline at end of file diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/TextFormatter.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/TextFormatter.kt index 64ef9c4..b74a02a 100644 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/TextFormatter.kt +++ b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/TextFormatter.kt @@ -11,7 +11,7 @@ class TextFormatter(private val regex: String) { private val decoroMaskGenerator = DecoroMaskGenerator() private val pcreGeneratorItem = regexReplaceGenerator.regexToRegexReplace(regex) private val regexReplaceString = pcreGeneratorItem.regexReplaceString - private val listForPlaceholder = pcreGeneratorItem.listForPlaceholder + private val listForPlaceholder = pcreGeneratorItem.list private val placeholderGenerator = PlaceholderGenerator(listForPlaceholder) fun getFormatText(inputText: String) = inputText.replace(Regex(regex), regexReplaceString) diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/DecoroMaskGenerator.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/DecoroMaskGenerator.kt index 3cf3841..4c73360 100644 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/DecoroMaskGenerator.kt +++ b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/DecoroMaskGenerator.kt @@ -11,11 +11,11 @@ class DecoroMaskGenerator { /** Генерация маски и слотов на основе возможных символов для placeholder, * если возможные символы не более одного, то символ хардкодится в слот * **/ - fun mask(placeholder: String, listForPlaceholder: List): MaskFormatWatcher { + fun mask(placeholder: String, listForPlaceholder: List>): MaskFormatWatcher { val slots = mutableListOf() for (i in placeholder.indices) { slots.add( - if (listForPlaceholder[i].length == 1) { + if (listForPlaceholder[i].size == 1) { PredefinedSlots.hardcodedSlot(placeholder[i]) } else { CustomValidator.customSlot(listForPlaceholder[i]) diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/PlaceHolderGenerator.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/PlaceHolderGenerator.kt index ca6cd3e..0431032 100644 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/PlaceHolderGenerator.kt +++ b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/PlaceHolderGenerator.kt @@ -1,90 +1,29 @@ package ru.touchin.roboswag.textprocessing.generators -import ru.touchin.roboswag.textprocessing.Constants.charsEngLower -import ru.touchin.roboswag.textprocessing.Constants.charsEngUpper -import ru.touchin.roboswag.textprocessing.Constants.charsRuLower -import ru.touchin.roboswag.textprocessing.Constants.charsRuUpper -import ru.touchin.roboswag.textprocessing.Constants.digits - class PlaceholderGenerator( - listForPlaceholder: List + listForPlaceholder: List> ) { private var placeholder: String = "" init { - /** Индексы для всех возможных вариантов: - * Цифр, Ангийских букв верхнего регистра, - * Русских букв верхнего регистра, - * Английских букв нижнего регистра, - * Русских букв верхнего и нижнего регистра, - * Английских букв верхнего и нижнего регистра, - * На случай остальных повторений - * **/ - var indexDigits = 0 - var indexCharsEngUpper = 0 - var indexCharsRuUpper = 0 - var indexCharsEngLower = 0 - var indexCharsRuLower = 0 - var indexUpNLowerRu = 0 - var indexUpNLowerEng = 0 - var indexElse = 0 - for (str in listForPlaceholder) { - if (str.isEmpty()) continue + val hashMap = hashMapOf, Int>() + for (listOfChar in listForPlaceholder) { + hashMap[listOfChar] = 0 + } + for (listOfChar in listForPlaceholder) { + if (listOfChar.isEmpty()) continue /** Если элемент без повторений **/ - if (str.length == 1) { - placeholder += str + if (listOfChar.size == 1) { + placeholder += listOfChar[0] continue } - when { - /** Если элемент повторяет цифры **/ - digits.contains(str) -> { - if (str.length <= indexDigits) indexDigits = 0 - placeholder += str[indexDigits] - indexDigits++ - } - /** Если элемент повторяет Английские буквы верхнего регистра **/ - charsEngUpper.contains(str) -> { - if (str.length <= indexCharsEngUpper) indexCharsEngUpper = 0 - placeholder += str[indexCharsEngUpper] - indexCharsEngUpper++ - } - /** Если элемент повторяет Английские буквы нижнего регистра **/ - charsEngLower.contains(str) -> { - if (str.length <= indexCharsEngLower) indexCharsEngLower = 0 - placeholder += str[indexCharsEngLower] - indexCharsEngLower++ - } - /** Если элемент повторяет Русские буквы верхнего регистра **/ - charsRuUpper.contains(str) -> { - if (str.length <= indexCharsRuUpper) indexCharsRuUpper = 0 - placeholder += str[indexCharsRuUpper] - indexCharsRuUpper++ - } - /** Если элемент повторяет Русские буквы нижнего регистра **/ - charsRuLower.contains(str) -> { - if (str.length <= indexCharsRuLower) indexCharsRuLower = 0 - placeholder += str[indexCharsRuLower] - indexCharsRuLower++ - } - /** Если элемент повторяет Русские буквы верхнего и нижнего регистра **/ - charsRuLower.contains(str[str.length - 1]) -> { - if (str.length <= indexUpNLowerRu) indexUpNLowerRu = 0 - placeholder += str[indexUpNLowerRu] - indexUpNLowerRu++ - } - /** Если элемент повторяет Аглийские буквы верхнего и нижнего регистра **/ - charsEngLower.contains(str[str.length - 1]) -> { - if (str.length <= indexUpNLowerEng) indexUpNLowerEng = 0 - placeholder += str[indexUpNLowerEng] - indexUpNLowerEng++ - } - /** Если элемент повторяет Другие символы **/ - else -> { - if (str.length <= indexElse) indexElse = 0 - placeholder += str[indexElse] - indexElse++ - } + hashMap[listOfChar]?.let { j -> + var i = j + if (listOfChar.size <= i) i = 0 + placeholder += listOfChar[i] + i++ + hashMap[listOfChar] = i } } } diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorItem.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorItem.kt index ba5d315..d9f7dd3 100644 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorItem.kt +++ b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorItem.kt @@ -2,5 +2,5 @@ package ru.touchin.roboswag.textprocessing.generators.regexgenerator class PCREGeneratorItem( val regexReplaceString: String, - val listForPlaceholder: List + val list: List> ) \ No newline at end of file diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListener.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListener.kt index 119450e..c371bf0 100644 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListener.kt +++ b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListener.kt @@ -1,6 +1,5 @@ package ru.touchin.roboswag.textprocessing.generators.regexgenerator -import ru.touchin.roboswag.textprocessing.Constants import ru.touchin.roboswag.textprocessing.pcre.parser.PCREBaseListener import ru.touchin.roboswag.textprocessing.pcre.parser.PCREParser @@ -9,7 +8,7 @@ class PCREGeneratorListener : PCREBaseListener() { * Лист для placeholder, где индекс - номер буквы для placeholder * значение - возможные символы для placeholder * **/ - private var mutableList = mutableListOf() + private var mutableListOfListChar = mutableListOf>() private var currentGroupIndex = 1 private var regexReplaceString = "" @@ -19,7 +18,7 @@ class PCREGeneratorListener : PCREBaseListener() { * [1-2], \\d, [A-B], а так же элементы не относящиеся к регулярным выражениям * или экранизированые * **/ - private var charsAtom = "" + private var charsList = mutableListOf() override fun enterCapture(ctx: PCREParser.CaptureContext) { super.enterCapture(ctx) @@ -30,8 +29,8 @@ class PCREGeneratorListener : PCREBaseListener() { override fun enterShared_atom(ctx: PCREParser.Shared_atomContext) { super.enterShared_atom(ctx) /** Найдено соответствие цифр \\d **/ - charsAtom = Constants.digits - mutableList.add(charsAtom) + charsList = '1'.rangeTo('9').toMutableList().apply { add('0') } + mutableListOfListChar.add(charsList) } override fun enterCharacter_class(ctx: PCREParser.Character_classContext) { @@ -41,37 +40,65 @@ class PCREGeneratorListener : PCREBaseListener() { * false - если, например [А-д] * **/ if (ctx.cc_atom().size > 1) { - charsAtom = "" + charsList = mutableListOf() val firstChar = ctx.CharacterClassStart().text val endChar = ctx.CharacterClassEnd()[0].text for (i in 0 until ctx.cc_atom().size) { - charsAtom += checkRules(firstChar + ctx.cc_atom()[i].text + endChar) + charsList += checkRules(firstChar + ctx.cc_atom()[i].text + endChar) } } else { - charsAtom = checkRules(ctx.text) + charsList = checkRules(ctx.text) } - mutableList.add(charsAtom) + mutableListOfListChar.add(charsList) } /** Дублирование повторений для placeholder при их наличии, например [A-B]{6}, где 6 - повторения **/ override fun enterDigits(ctx: PCREParser.DigitsContext) { super.enterDigits(ctx) repeat(ctx.text.toInt() - 1) { - mutableList.add(charsAtom) + mutableListOfListChar.add(charsList) } } override fun enterLiteral(ctx: PCREParser.LiteralContext) { super.enterLiteral(ctx) regexReplaceString += ctx.shared_literal().text - charsAtom = ctx.text - mutableList.add(charsAtom) + charsList = mutableListOf() + for (s in ctx.text) { + charsList.add(s) + } + mutableListOfListChar.add(charsList) } fun toPCREGeneratorItem() = PCREGeneratorItem( regexReplaceString, - mutableList.map { - it.replace("\\", "") - }.toMutableList() + mutableListOfListChar.map { it -> + it.filter { + it != '\\' + } + } ) + + private fun checkRules(ctxText: String): MutableList { + /** endAtomStr index of atomStr.length - 2 вычисляется потому что с поиском, например, + * в [A-B] должен проверяться последний допуск для строки в данном случае это В + * startAtomStr = atomStr[1] - потому что должен проверяться первый допуск для строки + * в [A-B] это будет А + * **/ + val endAtomStr = ctxText[ctxText.length - 2] + val startAtomStr = ctxText[1] + return if (startAtomStr.isLetterOrDigit() && endAtomStr.isLetterOrDigit()) { + getListRangeChars(ctxText).filter { + it.isLetterOrDigit() + }.toMutableList() + } else { + mutableListOf(startAtomStr, endAtomStr) + } + } + + private fun getListRangeChars(atomStr: String): MutableList { + val startRange = atomStr[1] + val endRange = atomStr[atomStr.length - 2] + return startRange.rangeTo(endRange).toMutableList() + } } \ No newline at end of file diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListenerExt.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListenerExt.kt deleted file mode 100644 index 00587e7..0000000 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/generators/regexgenerator/PCREGeneratorListenerExt.kt +++ /dev/null @@ -1,121 +0,0 @@ -package ru.touchin.roboswag.textprocessing.generators.regexgenerator - -import ru.touchin.roboswag.textprocessing.Constants - -data class IndexesItem(val firstIndex: Int, val lastIndex: Int) - -internal fun PCREGeneratorListener.checkRules(ctxText: String): String { - var atomStr = ctxText - var resultCharsAtom = "" - /** endAtomStr index of atomStr.length - 2 вычисляется потому что с поиском, например, - * в [A-B] должен проверяться последний допуск для строки в данном случае это В - * startAtomStr = atomStr[1] - потому что должен проверяться первый допуск для строки - * в [A-B] это будет А - * **/ - val endAtomStr = atomStr[atomStr.length - 2] - val startAtomStr = atomStr[1] - when { - atomStr.contains('-') -> { - when { - /** Проверка соответствия начала диапазона Русских букв на верхний регистр **/ - Constants.charsRuUpper.contains(startAtomStr) -> { - when { - /** Проверка соответствия диапазона Русских букв с верхним и нижнем регистром **/ - Constants.charsRuLower.contains(endAtomStr) -> { - atomStr = atomStr.uppercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsRuUpper) - resultCharsAtom = Constants.charsRuUpper.substring(firstIndex, lastIndex) + - Constants.charsRuLower.substring(firstIndex, lastIndex) - } - /** Проверка соответствия диапазона Русских букв с верхним регистром **/ - else -> { - atomStr = atomStr.uppercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsRuUpper) - resultCharsAtom = Constants.charsRuUpper.substring(firstIndex, lastIndex) - } - } - } - /** Проверка соответствия начала диапазона Русских букв на нижний регистр **/ - Constants.charsRuLower.contains(startAtomStr) -> { - when { - /** Проверка соответствия диапазона Русских букв с нижним и верхнем регистром **/ - Constants.charsRuUpper.contains(endAtomStr) -> { - atomStr = atomStr.lowercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsRuLower) - resultCharsAtom = Constants.charsRuLower.substring(firstIndex, lastIndex) + - Constants.charsRuUpper.substring(firstIndex, lastIndex) - } - /** Проверка соответствия диапазона Русских букв с нижним регистром **/ - else -> { - atomStr = atomStr.lowercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsRuLower) - resultCharsAtom = Constants.charsRuLower.substring(firstIndex, lastIndex) - } - } - } - /** Проверка соответствия начала диапазона Английских букв на верхний регистр **/ - Constants.charsEngUpper.contains(startAtomStr) -> { - when { - /** Проверка соответствия диапазона Английских букв с верхним и нижнем регистром **/ - Constants.charsEngLower.contains(endAtomStr) -> { - atomStr = atomStr.uppercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsEngUpper) - resultCharsAtom = Constants.charsEngUpper.substring(firstIndex, lastIndex) + - Constants.charsEngLower.substring(firstIndex, lastIndex) - } - /** Проверка соответствия диапазона Аглийских букв с верхним регистром **/ - else -> { - atomStr = atomStr.uppercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsEngUpper) - resultCharsAtom = Constants.charsEngUpper.substring(firstIndex, lastIndex) - } - } - } - /** Проверка соответствия начала диапазона Английских букв на нижний регистр **/ - Constants.charsEngLower.contains(startAtomStr) -> { - when { - /** Проверка соответствия диапазона Английских букв с нижним и верхнем регистром **/ - Constants.charsEngUpper.contains(endAtomStr) -> { - atomStr = atomStr.lowercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsEngLower) - resultCharsAtom = Constants.charsEngLower.substring(firstIndex, lastIndex) + - Constants.charsEngUpper.substring(firstIndex, lastIndex) - } - /** Проверка соответствия диапазона Аглийских букв с нижним регистром **/ - else -> { - atomStr = atomStr.lowercase() - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, Constants.charsEngLower) - resultCharsAtom = Constants.charsEngLower.substring(firstIndex, lastIndex) - } - } - } - /** Проверка соответствия диапазона Цифр букв с нижним регистром **/ - Constants.digits.contains(startAtomStr) -> { - /** Регулярки проверяют с 0, а placeholder с 1 **/ - val digitsRegex = "0123456789" - val (firstIndex, lastIndex) = findFirstAndLastIndex(atomStr, digitsRegex) - resultCharsAtom = digitsRegex.substring(firstIndex, lastIndex) - } - } - } - /** Результат при остальных соответствиях **/ - else -> { - resultCharsAtom = atomStr.substring(1, atomStr.length - 1) - } - } - return resultCharsAtom -} - -/** atomStr в себе должен содержать atomStr(описание выше) - * chars в себе должен содержать элементы по порядку алфавитному или возрастанию - * тех символов, которые находятся в atomStr - * **/ -internal fun PCREGeneratorListener.findFirstAndLastIndex(atomStr: String, chars: String): IndexesItem { - var firstIndex = 0 - var lastIndex = chars.length - 1 - for (i in chars.indices) { - if (chars[i] == atomStr[1]) firstIndex = i - if (chars[i] == atomStr[atomStr.length - 2]) lastIndex = i + 1 - } - return IndexesItem(firstIndex, lastIndex) -} \ No newline at end of file diff --git a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/validators/CustomValidator.kt b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/validators/CustomValidator.kt index 910c23f..9a27c90 100644 --- a/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/validators/CustomValidator.kt +++ b/text-processing/src/main/java/ru/touchin/roboswag/textprocessing/validators/CustomValidator.kt @@ -3,11 +3,11 @@ package ru.touchin.roboswag.textprocessing.validators import ru.tinkoff.decoro.slots.Slot class CustomValidator private constructor( - private val slotItems: String + private val slotItems: List ) : Slot.SlotValidator { companion object { - fun customSlot(slotItems: String) = Slot(null, CustomValidator(slotItems)) + fun customSlot(slotItems: List) = Slot(null, CustomValidator(slotItems)) } override fun validate(value: Char): Boolean {