Страница 1 из 4

регулярные выражения в программном коде

Добавлено: 15 дек 2022, 01:10
Olej
Это, в каком-то смысле, продолжение темы регулярные выражения в C/C++.
И публикации по её мотивам разошедшейся по Интернет под названием "Регулярные выражения C/C++", про которую (и ссылки) описано здесь: Локализация и регулярные выражения, C/C++.

Re: регулярные выражения в программном коде

Добавлено: 15 дек 2022, 01:17
Olej
Olej писал(а):
15 дек 2022, 01:10
И публикации по её мотивам
Но! :-(
1. Всё это было написано максимум в 2016 году ... кой чего можно бы добавить;
2. Это было только про регулярные выражения в коде C и C++ ... нужно дополнить коротко по состоянию дел в новых (современных) языках: Python, Go, Rust, Kotlin ...
3. С акцентом на использование (или на ограничения) регулярных выражений применительно к локализованным (в частности к русскоязычным) строкам.

Немало...

Re: регулярные выражения в коде

Добавлено: 16 дек 2022, 21:45
Olej
Olej писал(а):
15 дек 2022, 01:17
коротко по состоянию дел в новых (современных) языках: Python, Go, Rust, Kotlin ...
Python.
Ещё в начале этого года я бы рассматривал этот вопрос начиная с Python 2 ...
Но в 2022 году произошло очень большое (для меня, как по мне) событие: в основных дистрибутивах Linux, как итог 14-летних усилий (не так просто это оказалось!) дефаултной версией стал Python 3, и даже Python 2 по умолчанию не установлен в инсталляции, хотя и присутствует в стандартном репозитории для ручной установки ... см. Python: версии языка.
Т.е. это конец 22 летней истории Python 2.

Будем говорить только про Python 3 !

Код: Выделить всё

olej@R420:~$ python3 
Python 3.8.10 (default, Nov 14 2022, 12:59:47) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> re.__version__
'2.2.1'
>>> quit()

Re: регулярные выражения в программном коде

Добавлено: 16 дек 2022, 22:23
Olej
Olej писал(а):
16 дек 2022, 21:45
Python
Обработка текстовой информации вообще, и регулярные выражения как самый мощный механизм такой обработки, всё это очень органично вписывается в области использования Python. Поэтому ничего удивительного в том, что поддержка регулярных выражений входят в Python давно и естественным образом.
В Python работа с регулярными выражениями реализована в стандартном модуле re, который входит в стандартный дистрибутив Python (т. е. Ничего не нужно специально предпринимать для его использования):

Код: Выделить всё

$ python3 
Python 3.8.10 (default, Nov 14 2022, 12:59:47) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> re.__version__
'2.2.1'
>>> quit()
Несколько примеров того как используются операции модуля re:

Код: Выделить всё

$ cat regexp.py 
#!/usr/bin/python3
import re 

match = re.search(r'\d\d\D\d\d', r'Телефон 123-12-12') 
print(match[0] if match else 'Not found') 

match = re.search(r'\d\d\D\d\d', r'Телефон 1231212') 
print(match[0] if match else 'Not found') 

match = re.fullmatch(r'\d\d\D\d\d', r'12-12') 
print('YES' if match else 'NO') 
match = re.fullmatch(r'\d\d\D\d\d', r'Т. 12-12') 
print('YES' if match else 'NO') 

print(re.split(r'\W+', 'Где, скажите мне, мои очки??!')) 

print(re.findall(r'\d\d\.\d\d\.\d{4}', 
                 r'Эта строка написана 19.01.2018, а могла бы и 01.09.2017')) 

for m in re.finditer(r'\d\d\.\d\d\.\d{4}', r'Эта строка написана 19.01.2018, а могла бы и 01.09.2017'): 
    print('Дата', m[0], 'начинается с позиции', m.start()) 

print(re.sub(r'\d\d\.\d\d\.\d{4}', 
             r'DD.MM.YYYY', 
             r'Эта строка написана 19.01.2018, а могла бы и 01.09.2017')) 
Если функции re.search, re.fullmatch не находят соответствие шаблону в строке, то они возвращают значение None (а функция re.finditer не выдаёт ничего). А если соответствие найдено (что нас зачастую интересует), то возвращается match-объект. Это достаточно сложная структура, содержащая в себе кучу полезной информации о соответствии шаблону (полный набор атрибутов нужно смотреть в документации):
py.march.png
py.march.png (10.95 КБ) 444 просмотра
И то как это выполняется:

Код: Выделить всё

$ ./regexp.py
23-12
Not found
YES
NO
['Где', 'скажите', 'мне', 'мои', 'очки', '']
['19.01.2018', '01.09.2017']
Дата 19.01.2018 начинается с позиции 20
Дата 01.09.2017 начинается с позиции 45
Эта строка написана DD.MM.YYYY, а могла бы и DD.MM.YYYY

Re: регулярные выражения в программном коде

Добавлено: 16 дек 2022, 22:32
Olej
Olej писал(а):
16 дек 2022, 22:23
Несколько примеров того как используются операции модуля re:
Если шаблон регулярного выражения предстоит использовать неоднократно, его полезно предварительно компилировать (как уже было сказано ранее):

Код: Выделить всё

$ python3
Python 3.8.10 (default, Nov 14 2022, 12:59:47) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> regex = re.compile('\s+')
>>> regex.split('А роза упала на лапу Азора')
['А', 'роза', 'упала', 'на', 'лапу', 'Азора']
>>> type(regex)
<class 're.Pattern'>
Как уже показано выше, отрабатывать (тестировать) работу с регулярными выражениями можно в режиме интерпретатора:

Код: Выделить всё

$ python3
Python 3.8.10 (default, Nov 14 2022, 12:59:47)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> text = """
... 100 ИНФ  Информатика
... 213 МАТ  Математика
... 156 АНГ  Английский
... """
>>> import re
>>> regex_num = re.compile('\d+')
>>> regex_num.findall(text)
['100', '213', '156']
>>>

Re: регулярные выражения в программном коде

Добавлено: 16 дек 2022, 22:44
Olej
Olej писал(а):
15 дек 2022, 01:17
коротко по состоянию дел в новых (современных) языках: Python, Go, Rust, Kotlin ...
Go
Язык Go (компилирующий) в значительной мере является продолжателем линии языка C (и у основания этих языков стоят одни и те же лица, только с разрывом в 40 лет). Но, в противовес C/C++, язык Go изначально вводит для обработки символьной информации встроенный (builtin) тип строки string и обширный API строчной обработки. Поэтому язык никак не мог оставить в стороне работу с регулярными выражениями — GoLang имеет в своей стандартной библиотеке надежный пакет выражений, пакет regexp.

Код: Выделить всё

$ cat regexp.go
package main
import ("fmt"; "regexp")

func main() {
        matched, _ := regexp.MatchString("cat", "black cat meow")
        fmt.Println(matched)

        re, _ := regexp.Compile("cat")
        res := re.FindAllString("black cat meowcat", -1)
        fmt.Println(res)
}
Имя программы (модуля) regexp.go совпадает с именем паета реализующего регулярные выражения ... но это только "случайное" :lol: совпадение.
И выполнение:

Код: Выделить всё

$ go run regexp.go
true
[cat cat]
Показанное выше выполнение примера похоже на интерпретацию (как это было в случае Python), но это полноценная компиляция, выполняющаяся онлайн, с последующим выполнением.

Re: регулярные выражения в программном коде

Добавлено: 19 дек 2022, 01:36
Olej
Olej писал(а):
16 дек 2022, 22:44
коротко по состоянию дел в новых (современных) языках: Python, Go, Rust, Kotlin ...
Rust
Несмотря на то, что Rust ориентирован во многом как язык системного программирования, но и в нём, примерно с 2014 года, было введено библиотечное расширение (crate в терминологии Rust) regex. Это лишний раз указывает на то какую оценку такой технике дают разработчики языков.

Но в Rust всё гораздо хуже с использованием по сравнению с предыдущими... Т.е. по подключению крейта (библиотеки в терминологии Rust) regex:

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ rustc regex1.rs
error[E0432]: unresolved import `regex`
 --> regex1.rs:2:5
  |
2 | use regex::Regex;
  |     ^^^^^ maybe a missing crate `regex`?
  |
  = help: consider adding `extern crate regex` to use the `regex` crate

error: aborting due to previous error

For more information about this error, try `rustc --explain E0432`.

Re: регулярные выражения в программном коде

Добавлено: 19 дек 2022, 01:49
Olej
Olej писал(а):
19 дек 2022, 01:36
Т.е. по подключению крейта (библиотеки в терминологии Rust) regex:
Я не знаю как подключить внешний крейт regex (как и любой другой библиотечный крейт!) используя консольный компилятор rustc :

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ which rustc
/home/olej/.cargo/bin/rustc

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ rustc -V
rustc 1.64.0 (a55dd71d5 2022-09-19)

Которым компилировал простейшие коды Rust: Rust: новый подход к снаряду....
И, похоже, что этого не знают очень многие обсуждающие: Is it possible to use external crates like regex without cargo?
Does anyone know of a way to get a program to compile with only rustc and use external crates?, even if I have to manually download the crates source that is fine.
Это само по себе очень интересный вопрос, который нужно разрешить ... там в теме относительно Rust.

Re: регулярные выражения в программном коде

Добавлено: 19 дек 2022, 01:53
Olej
Olej писал(а):
19 дек 2022, 01:49
Я не знаю как подключить внешний крейт regex (как и любой другой библиотечный крейт!)
Но зато я знаю как создать проект с помощью менеджера проектов Rust cargo + как подключать к нему любые библиотечные крейты по зависимостям...

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ which cargo
/home/olej/.cargo/bin/cargo

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ cargo -V
cargo 1.64.0 (387270bc7 2022-09-16)
Создаём проект:

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ cargo new regexrs1
     Created binary (application) `regexrs1` package
Это типовой проект-заглушка:

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ tree regexrs1
regexrs1
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ cat regexrs1/Cargo.toml
[package]
name = "regexrs1"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ cat regexrs1/src/main.rs
fn main() {
    println!("Hello, world!");
}

Re: регулярные выражения в программном коде

Добавлено: 19 дек 2022, 01:56
Olej
Olej писал(а):
19 дек 2022, 01:53
как подключать к нему любые библиотечные крейты по зависимостям...
Подключаю библиотечный крейт:

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ cargo search regex
regex = "1.7.0"                    # An implementation of regular expressions for Rust. This implementation uses finite automata …
lazy-regex = "2.3.1"               # lazy static regular expressions checked at compile time
proc-macro-regex = "1.1.0"         # A proc macro regex library
regex-automata = "0.2.0"           # Automata construction and matching using regular expressions.
easy-regex = "0.11.7"              # Make long regular expressions like pseudocodes
readable-regex = "0.1.0-alpha1"    # Regex made for humans. Wrapper to build regexes in a verbose style.
human_regex = "0.2.3"              # A regex library for humans
regex_static = "0.1.1"             # Compile-time validated regex, with convenience functions for lazy and static regexes.
webforms = "0.2.2"                 # Provides form validation for web forms
hashtag-regex = "0.1.1"            # A simple regex matching hashtags accoding to the unicode spec: http://unicode.org/reports/tr…
... and 887 crates more (use --limit N to see more)

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ cat regexrs1/Cargo.toml
[package]
name = "regexrs1"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
regex = "1.7"
И переписываю в main.rs проекта свой исходный код:

Код: Выделить всё

olej@R420:~/2022/own.BOOKs/Localiz/regex.cod$ cat regexrs1/src/main.rs
use regex::Regex;

fn main() {
   let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
   assert!(re.is_match("2014-01-01"));
}
Всё! :lol: