{"id":21748351,"url":"https://github.com/surfstudio/maskinterpreter","last_synced_at":"2026-03-01T11:03:59.322Z","repository":{"id":71210887,"uuid":"205084423","full_name":"surfstudio/MaskInterpreter","owner":"surfstudio","description":null,"archived":false,"fork":false,"pushed_at":"2020-07-31T09:24:42.000Z","size":83,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":25,"default_branch":"master","last_synced_at":"2025-04-13T07:15:10.396Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/surfstudio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-08-29T05:04:08.000Z","updated_at":"2023-08-17T21:29:44.000Z","dependencies_parsed_at":"2023-03-23T04:21:01.276Z","dependency_job_id":null,"html_url":"https://github.com/surfstudio/MaskInterpreter","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/surfstudio/MaskInterpreter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2FMaskInterpreter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2FMaskInterpreter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2FMaskInterpreter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2FMaskInterpreter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/surfstudio","download_url":"https://codeload.github.com/surfstudio/MaskInterpreter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2FMaskInterpreter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29967932,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T10:55:55.490Z","status":"ssl_error","status_checked_at":"2026-03-01T10:55:55.175Z","response_time":124,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-26T08:13:09.818Z","updated_at":"2026-03-01T11:03:59.314Z","avatar_url":"https://github.com/surfstudio.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![codecov](https://codecov.io/gh/LastSprint/MaskInterpreter/branch/master/graph/badge.svg)](https://codecov.io/gh/LastSprint/MaskInterpreter)\n[![Actions Status](https://github.com/LastSprint/MaskInterpreter/workflows/CI/badge.svg)](https://github.com/LastSprint/MaskInterpreter/actions)\n# MaskInterpreter\n\nИнтерпритататор масок ввода из кастомного формата в формат [InputMask](https://github.com/RedMadRobot/input-mask-ios)\nЭта библиотека позволяет сделать две вещи:\n1. Транслировать одну грамматику в другую\n2. Проводить простой анализ грамматики и понимать:\n    - Минимальное и максимальное кол-во символов для ввода\n    - Тип клавиатуры для ввода (телефон, e-mail, просто цифры и т.д.)\n  \n## Грамматика\n\nИнтерпритатор позволяет сконвертировать одну грамматику в другую. \n\nРассмотрим грамматику, которую интерпритатор ожидает на вход:\n\n### Легенда\n\nВсе что внутри `\"\"` - константный символ. \nЗарезервированные символы:\n- `.` - Любой символ\n- `|` - Логическое ИЛИ\n- `(...)` - группа выражений\n- `+` - повторить предыдущее выражение 1 или более раз\n- `.` - любой символ\n\n### Токены\n\n```\nCONSTANT_SYMBOL = . \nSPECIAL_SYMBOL = \"\\\\d\" | \"\\\\w\" | \"\\\\s\" | \"\\\\D\" | \"\\\\W\" | \"\\\\S\"\nANY_SYMBOL = \".\"\nREPEATER_SYMBOL = \"+\" | \"*\"\nREGEXP_START_SYMBOL = \"\u003c!^\"\nREGEXP_END_SYMBOL = \"\u003e\"\nSLICE_SYMBOL = \"-\"\nONE_OF_START_SYMBOL = \"[\"\nONE_OF_END_SYMBOL = \"]\"\nRANGE_START_SYMBOL = \"{\"\nRANGE_END_SYMBOL = \"}\"\nRANGE_DELIMETER_SYMBOL = \",\"\nREGEXP_META_START_SYMBOL = \"$\"\n```\n### Правила\n\n```\nregexpSymbolRule = SPECIAL_SYMBOL  | CONSTANT_SYMBOL\n\nregexpSliceRule = CONSTANT_SYMBOL SLICE_SYMBOL CONSTANT_SYMBOL\n\nregexpOneOfRule = ONE_OF_START_SYMBOL regexpSliceRule | regexpSymbolRule ONE_OF_END_SYMBOL\n\nregexpRepeatSymbolRule = (ANY_SYMBOL | regexpSymbolRule | regexpOneOfRule) REPEATER_SYMBOL\n\nregexpBodyRule = regexpRepeatSymbolRule | regexpOneOfRule | regexpSymbolRule\n\nregexpRangeRule = RANGE_START_SYMBOL CONSTANT_SYMBOL (RANGE_DELIMETER_SYMBOL CONSTANT_SYMBOL)? RANGE_END_SYMBOL where CONSTANT_SYMBOL is NUMBER\n\nregexpMetaRule = REGEXP_META_START_SYMBOL regexpRangeRule\n\nregexpExpression = REGEXP_START_SYMBOL regexpBodyRule+ regexpMetaRule REGEXP_END_SYMBOL\n\nmaskExpression = (ConstantSymbol | regexpExpression)+\n```\n\n### Примеры \n\n`+7 (\u003c!^\\\\d+${3}\u003e)\u003c!^\\\\d+${3}\u003e-\u003c!^\\\\d+${2}\u003e-\u003c!^\\\\d+${2}\u003e` - маска для номера телефона. \n\nВсе что находится снаружи `\u003c!^...\u003e` это константы (автоматически подставляются), остальное - динамическая часть, которую должен вводить пользователь. \n\n`${x,y}` описывает кол-во символов для повтора (`\\\\d+${3}` означает повторить `\\\\d` ровно 3 раза)\n\n`\u003c!^[0-9А-Яа-яЁё\\\\s\\-]+${1,70}\u003e` - маска для обычного пользовательского ввода. \n\n**ВАЖНО**\n\nОдно динамическое выражение может содержать только 1 токен повторения.\n\n## Как использовать\n\n```Swift\n\nlet rawMask = \"\u003c!^\\\\d+${1,9}\u003e/\u003c!^\\\\d+${4}\u003e\"\n\nguard let mask = MaskInterpreter().interpret(rawMask: rawMask) else { return }\n\nlet maskNotations = mask.generated.notations.map { generated in\n  return Notation(character: generated.nameSymbol, characterSet: generated.set, isOptional: generated.isOptional)\n}\n\nself.maskInputLisnter.customNotations = maskNotations\nself.maskInputLisnter.primaryMaskFormat = mask.generated.mask\n```\n\n## Как установить\n\nCocoaPods:\n\n```\npod 'MaskInterpreter', :git =\u003e 'https://github.com/surfstudio/MaskInterpreter', :tag =\u003e '1.0.0'\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurfstudio%2Fmaskinterpreter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsurfstudio%2Fmaskinterpreter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurfstudio%2Fmaskinterpreter/lists"}