4.14 آموزش کار با regexp

4.14 آموزش کار با regexp

مواقعی در کد نویسی دارید که نیاز هست تا یک عبارتی مثل شماره تلفن،کد پستی و یا شماره پاسپورت وارد شده را بصورت قاعده مند بررسی کنید به عبارتی کاربر نتواند برای فیلد شماره تلفن، کاراکتر غیر عددی وارد کند. در این مواقع بهتر است داده وارد شده بصورت قاعده مند بررسی شود. برای درک بهتر موضوع به رشته وارد شده توسط کاربر که می تواند سهوا باشد دقت کنید

+989121234#566

در این رشته کاربر مرتکب دو اشتباه شده است.

  1. شماره موبایل یک رقم بیشتر وارد شده است
  2. کاربر بجای رقم از علامت # استفاده کرده است

در چنین شرایطی روش های بررسی مرسوم داده پاسخگو نیست و بهتر است از عبارات با قاعده استفاده کنیم.

در زبان برنامه نویسی Go بسته از پیش تعریف شده regexp برای اینکار وجود دارد.

1import (
2    "regexp"
3)

برای شروع و درک بهتر مطلب اجازه دهید از یک مثال ساده شروع کنیم. میخواهیم بررسی کنیم آیا کاربر کارکتر نقطه [.] را وارد کرده است یا خیر .

 1package main
 2
 3import (
 4    "fmt"
 5    "regexp"
 6)
 7
 8func main() {
 9    sampleRegex := regexp.MustCompile("[.]")
10    match := sampleRegex.Match([]byte("."))
11    fmt.Println(match)
12}

در کد فوق به کمک تابع MustCompile عبارت قاعده مند را دریافت می کنیم در صورتیکه عبارت وارد شده قابل قبول یا معتبر نباشد panic اتفاق خواهد افتاد . دقت داشته باشید که خود عبارت قاعده مند دارای استاندارد و چارچوب های مشخص است که بهتر است درصورت عدم اطلاع از ابتدا آن را بیاموزید.

دقت کنید که در کد فوق عبارت مد نظر خود را داخل [] قرار داده ایم و در خط بعد با تابع Match که مقدار مورد نظر را بصورت رشته ای از بایت ها به آن معرفی کرده ایم بررسی می کنیم که “.” در رشته وجود دارد یا خیر که خروجی این بررسی یک مقدار بولین بصورت ذیل است.

true

در واقع می توانید رشته های ساده را نیز با این روش مقایسه کنید بطور مثال :

 1package main
 2
 3import (
 4    "fmt"
 5    "regexp"
 6)
 7func main() {
 8    first := "abc"
 9    second := "xyz"
10    third := "123"
11    sampleRegex := regexp.MustCompile(first + second + third)
12
13    match := sampleRegex.Match([]byte("abcxyz123"))
14    fmt.Println(match)
15}

خروجی بررسی بالا

1$go run main.go
2true

اگر به کد فوق دقت کنید متوجه خواهید شد که مقادیر بررسی شده بصورت کامل بوده و چنانچه بررسی شما شامل بخشی از عبارت وارد شده باشد باز نتیجه بررسی اشتباه خواهد بود برای مثال ما قسمتی از کد را تغییر می دهیم

 1package main
 2...
 3func main() {
 4
 5	...
 6    match := sampleRegex.Match([]byte("abcxyz"))
 7
 8    fmt.Println(match)
 9
10}

در اینجا نتیجه بررسی برای عبارت “abcxyz” که در عبارت اصلی یعنی “abcxyz123” قرار دارد مقدار false نمایش داده خواهد شد که این به معنای بررسی کل عبارت است. برای رفع این اشتباه می بایست از ساختار عبارات قاعده مند بهر بگیریم و به این شکل به برنامه اطلاع دهیم که عبارت مد نظر ما می تواند بخشی از عبارت وارد شده باشد.

 1package main
 2import (
 3    "fmt"
 4    "regexp"
 5)
 6func main() {
 7    sampleRegex := regexp.MustCompile("[abc]")
 8    match := sampleRegex.Match([]byte("abcd"))
 9
10    fmt.Printf("For abcd: %t\n", match)
11    match = sampleRegex.Match([]byte("1abc23"))
12    fmt.Printf("For 1abc23: %t\n", match)
13
14    match = sampleRegex.Match([]byte("abc"))
15    fmt.Printf("For abc: %t\n", match)
16}

خروجی کد

1$go run main.go
2For abcd: true
3For 1abc23: true
4For abc: true

در کد فوق کارکترهای [] به این معنا است که عبارت مورد نظر می تواند شامل عبارت مورد مقایسه نیز باشد. به چند تا از علائم و معانی پرکاربرد در عبارات قاعده مند توجه کنید.

  1. \w فقط شامل حروف باشد
  2. \W شامل حروف نباشد
  3. \d شامل اعداد باشد
  4. \Dشامل اعداد نباشد
  5. \s شامل فضای خالی باشد
  6. \S شامل فضای خالی نباشد
  7. \+ شامل حداقل یک یا بیشتر باشد
  8. \* شامل صفر یا بیشتر باشد
  9. \| شامل عبارت مورد نظر و یا مورد دیگر باشد

لیست کامل این عبارات را می توانید در اینجا مشاهده کنید.

در مواقعی مایل هستیم که عبارت مورد نظر در رشته را جستجو و نمایش دهیم بطور مثال:

 1package main
 2
 3import (
 4	"fmt"
 5	"regexp"
 6)
 7
 8func main() {
 9	sampleRegexp := regexp.MustCompile(`(ab){2}`)
10
11	matches := sampleRegexp.FindString("abab")
12	fmt.Println(matches)
13
14	matches = sampleRegexp.FindString("ababbc")
15	fmt.Println(matches)
16}

در اینجا از برنامه خواسته ایم که به دنبال ترکیبی از ab با تکرار دوبار متوالی باشد و در انتها عبارت پیدا شده توسط تابع FindString را نمایش دهد که علامت () تاکید روی عبارت مورد نظر است و {2} به معنی تکرار حداقل دوبار متوالی است.

خروجی کد بالا

1$go run main.go
2abab
3abab

در پایان می خواهیم یک مثال سختر را که در ابتدا به آن اشاره کردیم بنویسیم و آن بررسی شماره تلفن است.

 1package main
 2
 3import (
 4	"fmt"
 5	"regexp"
 6)
 7
 8func main() {
 9	sampleRegexp := regexp.MustCompile(`^\+989(1[0-9]|3[1-9]|2[1-9])?[0-9]{7}$`)
10
11	matches := sampleRegexp.Match([]byte("+989121234#566"))
12	fmt.Println(matches)
13
14	matches = sampleRegexp.Match([]byte("+989121234567"))
15	fmt.Println(matches)
16}

خروجی کد بالا

1$ go run main.go
2false
3true

در کد فوق علامت ^ در عبارات با قاعده به معنی شروع ساختار عبارت است و علامت $ به معنای پایان عبارت. درواقع تمامی رشته های که قرار است عتبار سنجی شوند باید در ساختار بین این تو کاراکتر تطبیق شوند. در ادامه نیاز است تا با کمک کاراکتر \ اثر کارکتر + را خنثی کنیم به این معنی که تمامی شماره های وارد شده باید علامت + در ابتدا داشته باشند سپس قید شده است که 989 که پیش شمار ایران و موبایل است را قید کرده ایم . از آنجا که شماره موبایلهای ایران 911|912|913 شروع می شود با این عبارت “(1[0-9]|3[1-9]|2[1-9])” مشخص کرده ایم. علامت ؟ به معنی حداقل یکبار تکرار شده عبارت قبل خودش است و در انتها کاربر می بایست هفت رقم وارد که به این صورت مشخص شده است “[0-9]{7}”. همانطور مشاهده می کنید رشته اول معتبر نبوده ولی رشته دوم صحیح است.