Автор Тема: Регулярни изрази част 1  (Прочетена 17154 пъти)

0 Потребители и 1 Гост преглежда(т) тази тема.

Stan

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 27
  • -Получени: 135
  • Публикации: 641
Регулярни изрази част 1
« -: 18 Януари 2012, 21:45:18 »
Регулярните изрази по същество са един миниатюрен, високо специализиран език за програмиране.Използвайки този миниезик, вие определяте правилата, по които искате да подберете един набор от възможни пасващи символни низове.Този набор може да съдържа изречения на български, e-mail адреси или каквото пожелаете. По този начин можете да задавате въпроси от типа на: Дали този символен низ пасва на образеца?, или Съществува ли съвпадение с образеца някъде из този символен низ? Също така можете да използвате регулярните изрази за да модифицирате един символен низ или за да го разцепите по най-различни начини.

Преди да започнем, нека уточня, че използвам за програмен език php,съответно и PCRE функции-те за боравене с регулярни изрази, при които шаблоните ни от регулярни изрази задължително се обграждат с разделители(в случая съм използвал backslashes "/").За примерите по-долу може да използвате preg_match за тестване в php или някой engine.(Наш съфорумник е споделил един добър тук като при него наклонените черти обграждащи шаблона (/pattern/) се генерират автоматично и не е нужно да ги слагате)

Започваме с един лесен пример за регулярен израз:

Код: PHP
  1. $pattern='/hello/';

Така написан шаблона ни hello ще пасне(ще намери съвпадение) точно един път и точно със символния низ hello, независимо дали той съдържа други символи или само тези, тоест ако имаме символен низ hellohello регулярния израз ще намери първото съвпадение и ще спре до там:

Резултатa: hellohello

Казано по-точно, ако енджина, който борави с регулярните изрази открие съвпадение с шаблона ни символ по символ (проверява първо за съвпадение със символ h,ако се намери проверява за следващия e и т.н.),ще върне успех като резултат от търсенето.
Важно е да се отбележи, че шаблоните са чувствителни към регистъра,казано разбираемо правят разлика между малки и големи букви,разбира се това може да се избегне по много начини,но за тях по-късно.
Да започнем с основите на регулярните изрази така наречените метасимволи(специални символи,наречени още магически):

^ $ . * + ? { } [ \ | ( )

С какво те са по-различни от всички други символи? - ами имат определено значение тоест изпълняват определени задачи.
Започваме с първия метасимвол "^"(caret,коректорски знак) - какво значение има той ? - ами оказва началото на символния низ:

Код: PHP
  1. $pattern='/^hello/';

Ако използваме предишния символен низ "hellohello" регулярния израз ще намери същото съвпадение(hellohello), но то трябва задължително да е в началото на низа(всяко пространсво - интервал,табулация,нов ред или други непространствени символи отпред ще попречат да намери съвпадение).Точно това е разликата между този шаблон и предишния.При предишния не сме оказли изрично къде да се намира символния низ, който търсим дали е в началото или не и затова при него ще намери съвпадение независимо къде се намира той.Използван в началото на клас([^hp]) обаче изразява отрицание тоест търси се съвпадение на сивмоли различни в случая от "h" или "p" в символния низ, но за тази особеност ще поговорим в друг урок.

Метасимвола "$" (dollar,долар) е абсолютно идентичен като "^" само че той оказва края на символния низ :

Код: PHP
  1. $pattern='/hello$/';


Резултата както може би сами се досещате ще бъде: hellohello

Ако използваме заедно и двата метасимвола то създаваме правило, което казва че символния низ трябва да започва и съответно да завършва с шаблона ни.

Код: PHP
  1. $pattern='/^hello$/';

Ако изпозлваме отново символния низ от по-горе то няма да се намери съвпадение: hellohello
Точно затова са често използвани заедно за валидация на input полета или на get параметри.

Следващия "." (dot,точка) съвпада с един произволен символ(интервали,табулации и други пространства (без нов ред) или който и да е друг символ).Ще използваме отново същия символен низ по-горе:

Код: PHP
  1. $pattern='/./';


Резултата : hellohello

Другия метасимвол "*" (star,звезда) характеризира броя съвпадения, които ще открие регулярния израз - точно този прави следното: намира нула или повече съвпадения,тоест намирането на съвпадение на даден символ преди звездичката е незадължително.
Ще използваме за този пример символния низ: "heo"

Код: PHP
  1. $pattern='/hel*o/';

В случая задаваме правило: когато се стигне до символа "l" да провери за нула или повече негови съвпадения,ако няма както е в случая то да продължава да търси за съвпадение по останалите символи.

Резултата : heo

Метасимвола "+" (plus,плюс) е подобен на предишния,но има една значителна разлика - тук трябва да се намери задължително поне едно съвпадение с предишния символ и повече.Ако изпозлваме горния пример няма да открие съвпадение защото вместо "heo" регулярния израз търси "helo" или "hello" и изобщо "he(безброй много "l")o"

Код: PHP
  1. $pattern='/hel+o/';

Резултата със символен низ "helllllo": helllllo

Важно е да се отбележи, че тези два метасимвола "*" и "+" се наричат "алчни", защото могат да открият безброй много съвпадения и трябва да се внимава с употребата им.

Следващия "?" (question mark,въпросителен знак) е подобен на "*" с разликата, че тук се търсят нула или само едно съвпадение.Със следващия израз символния низ "heo" или "helo" ще бъде открит от регулярния израз но не и "hello" защото имаме повече от едно съвпадение на символа "l" пред метасимвола.Този метасимвол се използва също и за ограничаване на алчните.("+","*").

Код: PHP
  1. $pattern='/hel?o/';

Резултата със символен низ "helllllo": helllllo

Ако искаме да ограничим повторението на съвпаденията,тоест да направим някакъв интервал от х броя до y броя то изплзваме фигурните скоби "{x,y}".Вариянтите за създаване на такъв интервал са няколкo :
1.Имаме начална стойност(брой повторения), но нямаме крайна(до безкрайност) - {1,} (в този случай е идентично на "+")
2.Имаме начална, и крайна - {1,5}
3.Имаме точно определен брой повторения(нито повече,нито по-малко) - {3}

Код: PHP
  1. $pattern='/hel{1,3}o/';


Резултат с "hello": hello

За останалите метасимволи,с повече примери ще поговорим в следващия урок.

--> Към следващия урок.
« Последна редакция: 29 Юли 2012, 15:28:16 от Stan »

carrie

  • Newbie
  • *
  • Благодарности
  • -Казани: 1
  • -Получени: 0
  • Публикации: 8
Re: Регулярни изрази част 1
« Отговор #1 -: 13 Март 2012, 16:59:09 »
Здравей!

Искам да попитам как мога да напиша един регулярен израз, който да ми проверява имена като например това: Мария Иванова заедно с интервала, дали е написано на кирилица?
« Последна редакция: 13 Март 2012, 17:08:54 от vdimova »

Stan

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 27
  • -Получени: 135
  • Публикации: 641
Re: Регулярни изрази част 1
« Отговор #2 -: 13 Март 2012, 18:47:15 »
Здравей! Искам да попитам как мога да напиша един регулярен израз, който да ми проверява имена като например това: Мария Иванова заедно с интервала, дали е написано на кирилица?

Ами зависи каква кодирoвка използваш, ако си с ANSI долния пример би ти свършил работа:
/^(?:[а-яА-Я]+ ?)+$/Ако си с UTF8 ти предлагам да го направиш с unicode character properties, при които трябва да добавиш и флага(режима) "u" :
/^(?:\p{Cyrillic}+ ?)+$/uДобре е да прочетеш всички уроци ако има нещо неясно и да видиш примера за имена, който съм дал в тази тема.Този израз, който ти написах за разлика от израза в другата тема не е стриктен по отношение на това колко букви трябва да има в името и колко пъти да се повтаря то а проверява дали има една или повече букви от кирилицата като прихваща и единичен интервал между тях.

Успех!

ПП.Не уточни кой програмен език използваш,но предполагам си запозната с функциите му за работа с регулярните изрази.
« Последна редакция: 31 Юли 2012, 21:58:41 от Stan »

carrie

  • Newbie
  • *
  • Благодарности
  • -Казани: 1
  • -Получени: 0
  • Публикации: 8
Re: Регулярни изрази част 1
« Отговор #3 -: 14 Март 2012, 10:48:58 »
Вторият пример ми свърши перфектна работа. Благодаря много за помощта.  ;)
Езикът на който пиша е PHP и използвам preg_match.

howto

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 44
  • -Получени: 5
  • Публикации: 341
Re: Регулярни изрази част 1
« Отговор #4 -: 12 Юни 2012, 08:36:50 »
Браво за уроците !!!!!!!! Много добре си ги направил . Снощи започнах урок 1, и тествах всички /^$.?{} . Направих няколко примера и възникнаха въпроси.

Пример 1: $user['Райчо']['Ковачев'] = '/^Райчо Ковачев' .Знака ^ ще хване първия текст Райчо, но когато поставя примера така $user['Райчо']['Ковачев'] = '/^Райчо Ковачев$' не работи. Опитвам се да хвана в началото Райчо, и в края Ковачев.

Пример 2: $bad_usr_txt  е натрошил дизайна на сайта  като е спамил = "aaaaaaaaaaaaaaaaaaaaaaaaa";
Как мога да намеря текст, който има повече от 3 aaa ? Има ли възможност да кажа на израза ако открие повече от 3 ааа да ги заменя ? "/aaa+aaaaaaaaa/", 'спам'. Може би си го обяснил в другите уроци, но не съм стигнал до тях  .
 

Stan

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 27
  • -Получени: 135
  • Публикации: 641
Re: Регулярни изрази част 1
« Отговор #5 -: 12 Юни 2012, 12:04:11 »
Пример 1: $user['Райчо']['Ковачев'] = '/^Райчо Ковачев' .Знака ^ ще хване първия текст Райчо, но когато поставя примера така $user['Райчо']['Ковачев'] = '/^Райчо Ковачев$' не работи. Опитвам се да хвана в началото Райчо, и в края Ковачев.

Покажи примера как си го нраправил.

Как мога да намеря текст, който има повече от 3 aaa ? Има ли възможност да кажа на израза ако открие повече от 3 ааа да ги заменя ? "/aaa+aaaaaaaaa/", 'спам'. Може би си го обяснил в другите уроци, но не съм стигнал до тях.

Разбира се,че има, но не виждам смисъл в това.Ето ти два идентични примера:

Код: PHP
  1. preg_replace('/aaaa+/','spam',$text);
  2. preg_replace('/a{4,}/','spam',$text);

Но какво ще стане , ако потребителя напише "bbbbbb" или нещо друго или пък повтарящти се букви на кирилица? Това може да го използваш само за упражнение.Все пак може да се направи това, което искаш с регулярен израз.Целта е да мачне произволен символ(като изключим тези за пространства) който се повтаря 4 или повече пъти,като за целта ще използваме вътрешна референция към група:

Код: PHP
  1. preg_replace('/(\S)\1{3,}/u','spam',$text);

Но пък, ако имаме нещо от рода "многодългадумабезинтервали" където нямаме повторение на символ над 4 пъти, но отново ще ни счупи дизайна, то може да ползваме следния израз:

Код: PHP
  1. preg_replace('/\S{11,}/u','spam',$text);

Така всяка дума съдържаща повече примерно от 10 символа ще бъде заменяна.

Аз лично не бих го направил така, а с цсс.В стака преди време гледах тази тема. Като съм почти убеден че css свойството word-wrap: break-word; което е запазена марка на IE за тази цел е валидно и е предназначено също и за браузърите позлващи css3, тoест е типично css3 свойство.



howto

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 44
  • -Получени: 5
  • Публикации: 341
Re: Регулярни изрази част 1
« Отговор #6 -: 12 Юни 2012, 12:45:00 »
И аз използвах word-wrap: break-word;. Но при валидиране в wc3 го дава като грешка  :(Пък  и трябва да направим всичко възможно :) . Ако някой потребител не използва css1,2 ще стане грубо :) А и да прекъснеш дума по-дълга от 11 символа е грешка за мен . Но пък винаги има начин :) Аз често използвам това
Код: PHP
  1. $chars = str_split( $text, 100);
  2. foreach ( $chars as $char )
  3. {
  4.         /* izvikvane na sql infoto  */
  5.     echo "{$char}\n";
  6. }
Но и това не е добро решение.Ти си доста по-добър, време е да пуснеш един рег за справяне с този проблем :D . А аз започвам урок 2,че губим време ;)
« Последна редакция: 12 Юни 2012, 12:51:02 от howto »

Stan

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 27
  • -Получени: 135
  • Публикации: 641
Re: Регулярни изрази част 1
« Отговор #7 -: 12 Юни 2012, 14:46:24 »
И аз използвах word-wrap: break-word;. Но при валидиране в wc3 го дава като грешка  :(Пък  и трябва да направим всичко възможно :) . Ако някой потребител не използва css1,2 ще стане грубо :) А и да прекъснеш дума по-дълга от 11 символа е грешка за мен . Но пък винаги има начин :)

Мисля, че валидацията на css можеш да я преглътнеш.А относно това за 11-те символа просто го дадох като пример за брой символи, за това което искаше да направиш.Също с фунцията str_split() мисля, че ще имаш проблеми при кирилицата с UTF-8 кодировка на документа.Щом държиш толкова на това "чупене" на дълги думи ето ти един кратък пример как да го направиш с wordwrap() за латиница и кирилица(пак повтарям за пример просто използвам в случая числото 8 ):

Код: PHP
  1. function utf8_wordwrap($text,$w,$b,$c) {
  2.     $text = mb_convert_encoding($text,'cp1251','UTF-8');
  3.     $text = wordwrap($text,$w,$b,$c);
  4.     return mb_convert_encoding($text,'UTF-8','cp1251');
  5. }
  6. echo utf8_wordwrap($text, 8, "\n",true);

Ето ти и още един пример който прави същото нещо само че с помоща на регулярни изрази като плюса тук е, че азбуката, на която се пише ще бъде без значение:

Код: PHP
  1. function filter($match) { return preg_replace('/(\S{8})/u',"$1\n",$match[0]); }
  2. echo preg_replace_callback('/\S{9,}/u','filter',$text);

И пак повтарям, че за мен най-удачния начин е само и единствено чрез css.
 
ПП. Мисля, че се отклонихме достатъчно от идеята на урока.
« Последна редакция: 12 Юни 2012, 15:01:49 от Stan »

howto

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 44
  • -Получени: 5
  • Публикации: 341
Re: Регулярни изрази част 1
« Отговор #8 -: 16 Юни 2012, 09:24:28 »
Май,май ще чакаме хората да натиснат update browser version :P

georgirgeorgiev

  • Full Member
  • ***
  • Благодарности
  • -Казани: 77
  • -Получени: 13
  • Публикации: 164
Re: Регулярни изрази част 1
« Отговор #9 -: 25 Април 2015, 14:20:49 »
Благодаря Ви много за този урок.

БОГ да ви благослови.