TITextProcessing #1

Merged
vladimir.makarov merged 3 commits from feature/TITextProcessing into master 2023-04-21 11:27:16 +03:00

TITextProcessing

Библиотека для работы с регулярными выражениями

- TextFormatter

Класс TextFormatter представляет из себя сервис, принимающий регулярное выражение на вход и предоставляющий возможность генерации следующих объектов:

- Replacement template из getRegexReplacement();
- Placeholder из getRegexPlaceholder();
- Formatter text из getFormattedText(_ text: String)

func getRegexReplacement()

Метод, преобразующий входящее регулярное выражение в шаблон подстановки, например:

Input: (\\d{4}) ?(\\d{4}) ?(\\d{4}) ?(\\d{4})

Output: $1 $2 $3 $4

func getRegexPlaceholder()

Метод, преобразующий входящее регулярное выражение в текст-заполнитесь a.k.a placeholder, например:

Input: (\\d{4}) ?(\\d{4}) ?(\\d{4}) ?(\\d{4})

Output: 1234 5678 9012 3456

func getFormattedText(_ text: String) -> String

Метод, преобразующий входящий текст к нужному формату, заранее определенному посредством указания регулярного выражения, например:

Input: 2200111555550080

Output: 2200 1115 5555 0080

P.S. Учитываем, что TextFormatter был проинициализирован со слеюущим регулярным выражением: (\\d{4}) ?(\\d{4}) ?(\\d{4}) ?(\\d{4})

- RegexReplaceGenerator

Класс, отвечающий за генерацию PCREGeneratorItem из входящего регулярного выражения. Использует библиотеку Antlr4 и PCRE для работы.

static func generateReplacement(for regex: String) -> PCREGeneratorItem

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

let item = RegexReplaceGenerator. generateReplacement(for: "(\\d{2})\\/?(\\d{2})")

print(item.regexReplaceString)

/*
Выведет в консоль:
"$1\\/$2"
*/

print(item.matrixOfSymbols)

/*
Выведет в консоль:
[
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
	["/"],
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
]
*/

Итоговый PCREGeneratorItem содержит следующие данные:

regexReplaceString - итоговый шаблон подстановки для изначального регулярного выражения;

matrixOfSymbols - матрица символов, содержащая все возможные символы для каждого элемента в изначальном регулярном выражении

- RegexPlaceholderGenerator

Класс, отвечающий за генерацию текста-заполнителя a.k.a placeholder.

static func generatePlaceholder(matrixOfSymbols: [[Character]]) -> String

Функция, преобразующая входящую матрицу символов в текст-заполнитель, например:

let matrix: [[Character]] = [
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
	["/"],
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
	["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
]

let placeholder = RegexPlaceholderGenerator.generatePlaceholder(matrixOfSymbols: matrix)

print(placeholder)

/*
Выведет в консоль:
"12/34"
*/
# `TITextProcessing` ### Библиотека для работы с регулярными выражениями ## - `TextFormatter` Класс `TextFormatter` представляет из себя сервис, принимающий регулярное выражение на вход и предоставляющий возможность генерации следующих объектов: \- `Replacement template` из `getRegexReplacement()`; \- `Placeholder` из `getRegexPlaceholder()`; \- `Formatter text` из `getFormattedText(_ text: String)` #### `func getRegexReplacement()` Метод, преобразующий входящее регулярное выражение в шаблон подстановки, например: **Input**: `(\\d{4}) ?(\\d{4}) ?(\\d{4}) ?(\\d{4})`<br> **Output**: `$1 $2 $3 $4` #### `func getRegexPlaceholder()` Метод, преобразующий входящее регулярное выражение в текст-заполнитесь a.k.a placeholder, например: **Input**: `(\\d{4}) ?(\\d{4}) ?(\\d{4}) ?(\\d{4})`<br> **Output**: `1234 5678 9012 3456` #### `func getFormattedText(_ text: String) -> String` Метод, преобразующий входящий текст к нужному формату, заранее определенному посредством указания регулярного выражения, например: **Input**: `2200111555550080`<br> **Output**: `2200 1115 5555 0080` > P.S. Учитываем, что `TextFormatter` был проинициализирован со слеюущим регулярным выражением: `(\\d{4}) ?(\\d{4}) ?(\\d{4}) ?(\\d{4})` ## - `RegexReplaceGenerator` Класс, отвечающий за генерацию `PCREGeneratorItem` из входящего регулярного выражения. Использует библиотеку `Antlr4` и `PCRE` для работы. #### `static func generateReplacement(for regex: String) -> PCREGeneratorItem` Функция, преобразующий входящее регулярное выражение в структуру, содержащую шаблон подстановки и матрицу символов, например: ```swift let item = RegexReplaceGenerator. generateReplacement(for: "(\\d{2})\\/?(\\d{2})") print(item.regexReplaceString) /* Выведет в консоль: "$1\\/$2" */ print(item.matrixOfSymbols) /* Выведет в консоль: [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["/"], ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] ] */ ``` Итоговый `PCREGeneratorItem` содержит следующие данные: `regexReplaceString` - итоговый шаблон подстановки для изначального регулярного выражения;<br> `matrixOfSymbols` - матрица символов, содержащая все возможные символы для каждого элемента в изначальном регулярном выражении ## - `RegexPlaceholderGenerator` Класс, отвечающий за генерацию текста-заполнителя a.k.a placeholder. #### `static func generatePlaceholder(matrixOfSymbols: [[Character]]) -> String` Функция, преобразующая входящую матрицу символов в текст-заполнитель, например: ```swift let matrix: [[Character]] = [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["/"], ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] ] let placeholder = RegexPlaceholderGenerator.generatePlaceholder(matrixOfSymbols: matrix) print(placeholder) /* Выведет в консоль: "12/34" */ ```
vladimir.makarov added 4 commits 2023-04-17 17:28:40 +03:00
vladimir.makarov added 1 commit 2023-04-17 17:39:51 +03:00
vladimir.makarov added 1 commit 2023-04-18 19:21:49 +03:00
vladimir.makarov force-pushed feature/TITextProcessing from e0e47b4023 to c75e28b57f 2023-04-18 19:24:22 +03:00 Compare
vladimir.makarov force-pushed feature/TITextProcessing from c75e28b57f to 3e13729d08 2023-04-19 10:20:19 +03:00 Compare
vladimir.makarov requested review from ivan.smolin 2023-04-19 10:24:08 +03:00
vladimir.makarov requested review from nikita.semenov 2023-04-19 10:24:08 +03:00
vladimir.makarov force-pushed feature/TITextProcessing from 3e13729d08 to accdd8e28c 2023-04-19 14:18:55 +03:00 Compare
vladimir.makarov force-pushed feature/TITextProcessing from accdd8e28c to 93a8ee68f3 2023-04-19 14:22:11 +03:00 Compare
ivan.smolin reviewed 2023-04-19 14:33:56 +03:00
@ -0,0 +22,4 @@
import Foundation
public final class RegexPlaceholderGenerator {
Member

Я бы назвал его DefaultRegexPlaceholderGenerator и, в будущем, создал интерфейс и оставил открытые методы для тюнинга на проектах.

Я бы назвал его `DefaultRegexPlaceholderGenerator` и, в будущем, создал интерфейс и оставил открытые методы для тюнинга на проектах.
vladimir.makarov marked this conversation as resolved
ivan.smolin reviewed 2023-04-19 14:36:53 +03:00
@ -0,0 +12,4 @@
s.source_files = s.name + '/Sources/**/*'
s.static_framework = true
Member

а это зачем?

а это зачем?
vladimir.makarov marked this conversation as resolved
ivan.smolin reviewed 2023-04-19 14:36:57 +03:00
@ -0,0 +13,4 @@
s.source_files = s.name + '/Sources/**/*'
s.static_framework = true
s.user_target_xcconfig = { 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
Member

и это?

и это?
vladimir.makarov marked this conversation as resolved
ivan.smolin reviewed 2023-04-19 14:40:26 +03:00
@ -0,0 +69,4 @@
public override func enterShared_atom(_ ctx: PCREParser.Shared_atomContext) {
super.enterShared_atom(ctx)
listOfSymbols = "1234567890".map { Character(String($0)) }
Member

проще это вынести в константу

проще это вынести в константу
ivan.smolin reviewed 2023-04-19 14:41:46 +03:00
@ -0,0 +115,4 @@
/*
If there is a {1,2} duplication then take the last one to maximize the output placeholder
*/
if let quantifierString = ctx.getText().components(separatedBy: CharacterSet.decimalDigits.inverted).filter({ !$0.isEmpty }).last,
Member

а нельзя из QuantifierContext это получить?

а нельзя из QuantifierContext это получить?
Author
Member

Да вот как будто бы нельзя, прошелся по всем основным методам, корректные данные возвращает только getText()

Да вот как будто бы нельзя, прошелся по всем основным методам, корректные данные возвращает только `getText()`
ivan.smolin marked this conversation as resolved
ivan.smolin reviewed 2023-04-19 14:42:09 +03:00
@ -0,0 +124,4 @@
If there is an infinite duplication option through "+" sign then duplicate it 5 times
*/
if ctx.getText() == "+" {
count = 5
Member

в константу

в константу
vladimir.makarov marked this conversation as resolved
ivan.smolin reviewed 2023-04-19 14:48:52 +03:00
@ -0,0 +164,4 @@
private func getAvailableSymbols(for ctxText: String) -> [Character] {
let startAtomStr = ctxText[ctxText.index(after: ctxText.startIndex)]
let endAtomStr = ctxText[ctxText.index(ctxText.endIndex, offsetBy: -2)]
Member

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

а если пустой или только один символ в строке? такого не может быть?
Author
Member

Даже если один символ в диапазоне, то в ctxText будет приходить [A] (например), соответственно, с offset все отработает корректно

Даже если один символ в диапазоне, то в `ctxText` будет приходить `[A]` (например), соответственно, с `offset` все отработает корректно
ivan.smolin marked this conversation as resolved
ivan.smolin reviewed 2023-04-19 14:51:38 +03:00
@ -0,0 +25,4 @@
public final class RegexReplaceGenerator {
public static func generateReplacement(for regex: String) -> PCREGeneratorItem {
Member

нейминг класса и метода кажется неудачным

также listerner надо прокидывать в init с дефолтным значением

нейминг класса и метода кажется неудачным также listerner надо прокидывать в init с дефолтным значением
Author
Member

Хм, а какое лучше название тогда указать? Что-то связанное с PCREItem или что-то другое?

Хм, а какое лучше название тогда указать? Что-то связанное с `PCREItem` или что-то другое?
Member

сам не могу придумать

сам не могу придумать
ivan.smolin reviewed 2023-04-19 14:52:05 +03:00
@ -0,0 +23,4 @@
import Foundation
import Antlr4
public final class PCREGeneratorListener: PCREBaseListener {
Member

я бы назвал Default*** и оставил open

я бы назвал Default*** и оставил open
vladimir.makarov marked this conversation as resolved
nikita.semenov reviewed 2023-04-19 22:17:09 +03:00
@ -0,0 +42,4 @@
public func getFormattedText(_ text: String) -> String {
guard let expression = try? NSRegularExpression(pattern: regex, options: .caseInsensitive) else {
fatalError("Cannot create NSRegularExpression from input regex")
Member

А тут точно безопасно fatalError делать?

А тут точно безопасно `fatalError` делать?
Author
Member

В данном случае мы явно показываем пользователю, что переданное им регулярное выражение - некорректно, в связи с чем не очень правильно выдавать ему отформатированный текст, основываясь непонятно на какие правила. Как мне кажется, уж лучше выкинуть fatalError в таком случае

В данном случае мы явно показываем пользователю, что переданное им регулярное выражение - некорректно, в связи с чем не очень правильно выдавать ему отформатированный текст, основываясь непонятно на какие правила. Как мне кажется, уж лучше выкинуть `fatalError` в таком случае
nikita.semenov marked this conversation as resolved
vladimir.makarov added 1 commit 2023-04-20 12:31:16 +03:00
ivan.smolin approved these changes 2023-04-20 19:20:43 +03:00
nikita.semenov reviewed 2023-04-20 22:10:10 +03:00
@ -0,0 +172,4 @@
listOfSymbols.removeAll()
}
// MARK: - Private methods
Member

теперь это видимо Public methods ))

теперь это видимо `Public methods` ))
nikita.semenov approved these changes 2023-04-20 22:11:04 +03:00
vladimir.makarov added 1 commit 2023-04-21 11:23:21 +03:00
vladimir.makarov merged commit fc6a735d94 into master 2023-04-21 11:27:16 +03:00
vladimir.makarov deleted branch feature/TITextProcessing 2023-04-21 11:27:51 +03:00
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: TouchInstinct/LeadKit#1
No description provided.