Програмд текст боловсруулах шаардлага маш их гардаг. Тухайлбал текст залгах, таслах, үг хайх, хувиргах гэх мэт. Текст боловсруулалтад регуляр илэрхийллийг өргөн ашигладаг.
Текст дотор хэв тавьж хайлт хийх нь эртний програмчлалаас улбаатай юм. 1960-ээд оны дундаас SNOBOL хэлэнд текст задлан ялгах зорилгоор тусгай илэрхийлэл ашиглаж байсан. Энэ нь цаашлаад Unix орчны grep багаж үүсэхэд зохих үүрэг гүйцэтгэсэн. Perl, grep болон бусад скрипт хэл дээр ажиллаж байсан туршлагатай хүмүүсийн хувьд регуляр илэрхийлэл нь танил зүйл юм.
Хэв тааруулах нь текстэн өгөгдлөөс тодорхой хэвд тохирох текст обектийг хайх, гарган авах энгийн зарчим дээр тулгуурлана. Хэв болгон ашиглаж байгаа тэмдэгт мөрийг регуляр илэрхийлэл гэнэ.
Хэв зохиоход мета-тэмдэгт гэж нэрлэгдэх тусгай тэмдэгтүүдийг ашигладаг. Эдгээр тэмдэгтийг 4 ангилж болно:
- Хэв тааруулах тэмдэгт. Жишээ нь
\d
нь 0 -ээс 9 хүртэлх тэмдэгттэй тохирно. - Давтах тэмдэгт. Хэв тэмдэгтүүдийг давтаж бичихийн оронд давтах тэмдэгтүүд оруулж болно—жишээлбэл,
\d\d\d
хэвний оронд\d{3}
гэж ашиглаж болно. - Байрлуулах тэмдэгт. Хэвэнд тохирох илэрцийн байрлалыг заана—жишээ нь,
^\d{3}
хэв нь илэрц мөрийн эхэнд олдохыг шаардана. - Эскэйп тэмдэгт. Тэмдэгтүүдийн өмнө гэдрэг налуу (
\
) ашиглана, эсрэг тохиолдолд утга нь өөр болно—жишээ нь,\}
нь баруун хаалтын илэрцийг заана.
Дараах хүснэгтэд хамгийн нийтлэг хэрэглэгддэг хэв тэмдэгтүүдийг харуулсан байна.
Хэв | Тохироо нөхцөл | Жишээ |
---|---|---|
+ |
Өмнөх элементийн нэг буюу хэд хэдэн илэрц. | too ба tooo нь to+ хэвтэй тохирно. Харин t тохирохгүй. |
* |
Өмнөх элементийн хоосон буюу хэд хэдэн илэрц. | t эсвэл too эсвэл tooo нь to* хэвтэй тохирно. |
? |
Өмнөх элементийн хоосон буюу яг нэг илэрц. | ten эсвэл tn нь te?n хэвтэй тохирно. Харин teen тохирохгүй. |
{n} |
Өмнөх элементийн n ширхэг илэрц. |
teen нь te{2}n хэвтэй тохирно. ten эсвэл teeen тохирохгүй. |
{n,} |
Өмнөх элементийн хамгийн багадаа n илэрц. |
ten ба teen нь te{1,}n хэвтэй тохирно, харин tn тохирохгүй. |
{n,m} |
Өмнөх элементийн хамгийн багадаа n ихдээ m ширхэг илэрц. |
ten ба teen нь te{1,2}n хэвтэй тохирно. |
\ |
+ , * , ? гэх мэт тусгай утгатай тэмдэгт хайхад ашиглана. |
A\+B хэв нь A+B тэй тохирно. |
\d \D |
Дурын цифр (\d ) эсвэл цифр бус тэмдэгтийн (\D ) илэрц. Энэ нь харгалзан [0-9] эсвэл [^0-9] тэй адил. |
\d\d нь 55 -тай тохирно. \D\D нь ab -тэй тохирно. |
\w \W |
Дурын үг, мөн доогуур зураас (\w ) эсвэл үг бус (\W ) тэмдэгтийн илэрц. \w нь [a-zA-Z0-9_] тэй тэнцүү. \W нь [^a-zA-Z0-9_] тэй тэнцүү. |
\w\w\w\w нь A_19 тэй тохирно. \W\W\W нь ($) тэй тохирно. |
\n \r \t \v \f |
Шинэ мөр, мөрийн эхэнд шилжилт, тааб, босоо тааб, форм фийд. | |
\s \S |
Сул зай (\s) эсвэл сул зай бус тэмдэгтийн илэрц (\S). Сул зай нь хоосон болон тааб тэмдэгтүүд юм. | A B C нь \w\s\w\s\w хэвтэй тохирно. |
. |
Дурын нэг тэмдэгт. | abc нь a.c хэвтэй тохирно. Харин abcc тохирохгүй. |
| | Логик OR. | enquiry нь in |en хэвтэй тохирно. |
[...] |
Хаалтанд бичсэн нэг тэмдэгтийн илэрц. Цэгүүдийг муж заахад ашиглаж болно. | [aeiou] нь u тэй тохирно. [\d\D] нь нэг цифр эсвэл цифр бус тэмдэгттэй тохирно. |
[^...] |
Хаалтад зааснаас бусад тэмдэгт. | x нь [^aeiou] хэвтэй тохирно. |
Жишээ болгон машины дугаар хайх хэв зохиоё:
[А-Я]{3}-\d{2}-\d{2}
Хэвийг уншвал “Дараалсан 3 крилл үсэг - Дараалсан 2 цифр – Дараалсан 2 цифр” гэсэн хэллэг болно.
Илэрцийн байрлалыг заах тэмдэгтүүдийг харуулсан байна. Эдгээр тэмдэгтүүд нь илэрц хаана таарахыг заахаас бус хайлтын ажиллагаанд нөлөө үзүүлэхгүй.
Тэмдэгт | Тайлбар |
---|---|
^ |
Илэрц текстийн эхэнд таарна |
$ |
Илэрц текстийн төгсгөлд таарна |
\A |
Өмнөх хэвтэй тохирох илэрц мөрийн эхэнд олдох. |
\b \B |
Үгэн (үсэг, тооноос бүтсэн) хүрээнд байрлуулах (\b ), үгэн бус хүрээнд байрлуулах (\B ). |
\z \Z |
Илэрц мөрийн төгсгөлд таарна (\z ), мөрийн төгсгөлийн тэмдэгтийн өмнө. |
Жишээ нь машины дугаар тааруулахдаа бид байрлалаар нь хязгаарлалт хийж болно. Тухайлбал, дугаар мөрийн эхэнд эсвэл төгсгөлд таарахаар нөхцөл тавия.
^[А-Я]{3}-\d{2}-\d{2}$
Төрөл бүрийн зориулалтаар нийтлэг хэрэглэгддэг регуляр илэрхийллүүдийг интернэтээс олох боломжтой байдаг. Жишээлбэл www.regexlib.com сайт дээр төрөл бүрийн зориулалттай регуляр илэрхийллүүд байдаг.
Go хэлний regexp
сан нь RE2 стандартын дагуу регуляр илэрхийлэл боловсруулалтыг дэмжинэ. Энэ сан нь хэв ашиглан текст хайх, засварлах функцүүдийг агуулдаг. Тухайлбал хайлт хийхэд зориулсан Match
, Find
, FindAll
нэртэй функцүүд бий. Эдгээр функцүүд оролтын эх үүсвэрээс хамаараад MatchReader
, MatchString
, FindString
, FindAllString
гэх мэт хувилбаруудтай.
Жишээ нь IP хаяг зөв эсэхийг шалгахад regexp.MatchString()
функцийг ашиглаж болно. Юуны өмнө эхлээд хэвээ зохиох хэрэгтэй. IP хаяг нь 4 хэсгээс тогтох ба хэсэг тус бүрд 1-3 оронтой бүхэл тоо байдаг. Хайлтын хэвийг бичвэл дараах байдалтай болно:
^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9] {1,3}$
Дээрх хэвд [0-9]{1,3}\\.
хэлбэрийн бичиглэл 3 удаа давтагдаж байгааг ажиглаарай. Тиймээс бага зэрэг товчилж болно. Үүнд хэвийг давтах {}
тэмдэгтийг ашиглая.
^([0-9]{1,3}\\.){3}[0-9]{1,3}$
Ингээд зохиосон хэвээ ашиглан өгөгдсөн текст IP хаяг мөн эсэхийг шалгах функц бичие.
func IsIP(str string) bool {
m,_:=regexp.MatchString("^([0-9]{1,3}\\.){3}[0-9]{1,3}$", str)
return m
}
Өөр нэг тооны формат шалгах жишээ авая. Тоо нь бүхэл эсвэл бутархай хэлбэртэй байж болно, мөн +
, -
тэмдэгээр эхэлж болно. Жишээлбэл 98
, 12.0
, +2.3
гэх мэт.
func IsNumber(str string) {
m, _ := regexp.MatchString("^[+-]?\\d*\\.?\\d*$", str)
return m
}
Текст дотор дэд мөр хайхад зориулсан 16 функц бий. Тэдгээрийн нэрний бүтцийг регуляр илэрхийллээр дүрсэлвэл:
Find(All)?(String)?(Submatch)?(Index)?
Хэрэв нэрэнд All
орсон бол үл давхардах бүтэн илэрцүүдийг бүгдийг олж буцаана.
String
орсон бол байт массив биш тэмдэгт мөр дамжуулах хэрэгтэй.
Хэрэв Submatch
орсон бол үндсэн илэрцээс гадна дэд илэрцүүдийг буцаана. Дэд илэрцийг дугуй хаалтаар тэмдэглэнэ.
Хэрэв Index
орсон бол илэрцийн байрлалыг буцаана.
Жишээ 1: Текстээс FindAllString()
ашиглан бүх тоог ялгаж харуулах
re,_:=regexp.Compile("[+-]?\\d+\\.?\\d*")
all := re.FindAllString(“9 сарын 1”, -1)
fmt.Println("FindAllString = ", all)
// Үр дүн: [“9” “1”]
Энэ жишээнд regexp.Compile
функцийг ашигласан байна. Энэ функц нь хэвийг шалгаж хөрвүүлээд Regexp
төрлийн обект үүсгэдэг. Нэг хэвийг олон дахин ашиглах бол Regexp
обект үүсгэн ашиглах нь тохиромжтой байдаг.
FindString
функцийн хоёр дахь параметр нь сөрөг утгатай бол боломжит бүх илэрцийг буцаана, эерэг утгатай бол илэрцийн тоог уг утгаар хязгаарладаг.
Жишээ 2: Дэд илэрц хайх
re := regexp.MustCompile("a(x*)b(y|z)c")
fmt.Printf("%q\n", re.FindStringSubmatch("-axxxbyc-"))
fmt.Printf("%q\n", re.FindStringSubmatch("-abzc-"))
}
// ["axxxbyc" "xxx" "y"]
// ["abzc" "" "z"]
“xxx”, “y” утгууд нь “axxxbyc” илэрц доторхи дэд илэрц юм.
Жишээ 3: Долоо хоногын цаг агаарын мэдээ агуулсан мөрийг задлах
string txt ="Даваа Дээд:26 Доод:21 Мягмар Дээд:23 Доод:20";
FindAllStringSubmatch()
функцийг ашиглах ба хайлт хийх регуляр илэрхийлэл нь 3 группыг агуулна: гаригийн нэр, дээд температур, доод температур.
package main
import (
"regexp"
"fmt"
)
func main() {
txt :="Даваа Дээд:26 Доод:21 Мягмар Дээд:23 Доод:20"
re,_:=regexp.Compile(`([а-яА-Я]+)\s*Дээд:(\d+)\s*Доод:(\d+)`)
all := re.FindAllStringSubmatch(txt, -1)
for _, m := range all {
fmt.Printf("%s: %s-%s\n", m[1], m[2], m[3])
}
}
// Даваа: 26-21
// Мягмар: 23-20
Дээрх жишээнд регуляр илэрхийллийг ` ` тэмдэгтээр хашсан байгааг анзаараарай. Энэ тохиолдолд \s
зэрэг тусгай тэмдэгтүүдэд давхар налуу зураас (\\
) хэрэглэх шаардлагагүй болно.
regexp
сангийн ReplaceAll
, ReplaceAllString
функцүүд нь хэвээр хайлт хийгээд таарсан илэрцийг өгсөн утгаар солино. Солилт яаж хийгдэх, хайлтыг хаанаас эхлэх зэргийг заах боломжтой хэд хэдэн хувилбар байдаг.
Жишээ 1: HTML кодон дотроос <script>
элементүүдийг хасая.
re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
src = re.ReplaceAllString(src, "")
Жишээ 2: Үгийн алдаа засах. Дараах жишээнд i
үсгүүдийг o
үсгээр сольж засаж байна.
re := regexp.MustCompile("i")
fmt.Println(re.ReplaceAllString("sift rise", "o"))
// soft rose
Жишээ 3: Үгийн байрлал солих
re := regexp.MustCompile(`(\w+),\s*(\w+)`)
fmt.Println(re.ReplaceAllString("one, two", "$2, $1"))
// two, one
Дээрх жишээнд $1
, $2
тэмдэглэгээг ашигласан байна. $
тэмдэг нь олдсон дэд илэрцийг заадаг. Жишээ нь $1
нь эхний дэд илэрцийг заана. Тэгэхээр $2, $1
текст нь хоёр дахь илэрцийг эхэнд нь, эхний илэрцийг хоёр дахь байрлалд сольж тавина гэсэн заавар болно.
regexp.Split()
функц нь текст мөрийг илэрц олдсон цэгүүдээр хувааж массивт байрлуулна. Энэ функц нь strings
сангийн Split
функцтэй төстэй, гэхдээ хуваагч тэмдэгт заахын оронд регуляр илэрхийлэл хэрэглэнэ.
Жишээ нь өнгөний нэрс агуулсан текст байна. Нэрсийн хооронд таслал, цэг таслал, сул зай гэх мэт тусгаарлагч тэмдэгтүүд байна. Энэ текстээс өнгөний нэрсийг ялгаж харуулах програм зохиоё.
package main
import (
"fmt"
"regexp"
)
func main() {
colorText:="улаан,ногоон шар;цэнхэр"
re := regexp.MustCompile("[,;\\s]")
fmt.Printf("%q\n", re.Split(colorText, -1))
}
// ["улаан" "ногоон" "шар" "цэнхэр"]