Reguláris kifejezések

 

A PHP esetén több függvénykönyvtárból is választhatunk, ha reguláris kifejezésekkel szeretnénk foglalkozni: az egyik a POSIX kompatibilis ereg_* függvény család, valamint a Perl kompatibilis PCRE csomag által nyújtott preg_* funkciók. Mi az ereg_* függvényekkel nem foglalkozunk, mert több szempontból is szerényebb képeségekkel bír, mint a PCRE csomag: egyrészt lassabb is (egyes becslések szerint körülbelül 30%-kal), másrészt kevesebb lehetõséget is nyújt.

Reguláris kifejezésekkel kapcsolatban érdemes megemlíteni, hogy némileg közhiedelem, hogy lassúak, általában már nagyon egyszerû feladatok esetén is alig lassabb, mint a sima szöveg kezelõ függvények, de kicsit is összetettebb feladatok esetén szinte biztosan állítható, hogy jobban járunk egy jól irányzott reguláris kifejezéssel, mintha szöveg kezelõ funkciók sorozatával oldanánk meg az adott problémát. Persze ha valamit megoldhatunk egyetlen strpos, str_replace parancs segítségével, akkor felesleges regexpeket használni.

Mire is jók a reguláris kifejezések? Reguláris kifejezésekkel szövegek egy halmazát tudjuk általánosan leírni, mégpedig úgy, hogy egy ezeket egy speciális jelentéssel bíró metakaraktereket tartalmazó mintával határozzuk meg. Elõször is nézzük át, hogy milyen elemek találhatóak egy reguláris kifejezésben:
o karakterek: minden nem metakarakter karakter saját magát jelenti
o : escape karakter, ezzel érhetjük el, hogy amúgy speciális jelentéssel bíró karakterekre is hivatkozni tudjunk
o karakter megadási módok:
– rövidítések: n, t, r stb.
– oktális forma: ddd (ddd az oktális szám)
– hexa forma: xhh
– unicode hexa forma: x{hh..}, uhh.. (u módosító kell hozzá)
– kontroll karakterek: cx (x tetszõleges karakter)
o karakter osztályok:
– .: a pont általában tetszõleges karaktert határoz meg kivéve az újsor
– C: egy byte-ot jelent
– X: egy unicode szekvenciát jelent (u módosító kell hozzá)
– w, W: egy tetszõleges szóban elõfordulható karakter, illetve ennek fordítotja (locale függõ)
– d, D: egy tetszõleges szám karaktert, illetve ennek fordítottja
– s, S: tetszõleges whitespace karakter, illetve ennek fordítottja
– az elõbi 3 esetén érdekes lehet, hogy csak ASCII karaktereket találnak meg, ezért Unicode karakterek esetén használjuk a megfelelõ p{X}, pX karakter osztályokat
– p{X}, pX: Unicode karaktereket szûrhetünk a tulajdonságaik alapján (L-Letter, N-Number, Z-Separator stb.)
– P{X}, PX: az elõbbi ellentéte (PL -> nem betû)
– []: saját karakter osztályok
o metakarakterek karakter osztályon belül: (escape), ^ (negálás), – (tartomány megadása), ] (karakter osztály lezárása)
o [a-zA-Z0-9], [^a-z], [ntrCXwWdDsSb…..]
o horgonyok:
– ezek feltételeket határoznak meg, nulla hosszúságúak (nem fogyasztanak el karaktert a szövegbõl)
– ^, $: szöveg eleje és vége (m módosító esetén újsor karakterre is illeszkednek)
– A, z, Z: szöveg eleje, vége, vége vagy vége elõtti újsor karakter (függetlenek az m módosítótól)
– G: illesztés kezdeténél illeszkedik (preg_match 5. paramétere határozza meg)
– b, B: szó határon illeszkedik, illetve annak ellentétje (szintén locale függõ, valamint karakter osztályon belül a b backspace karaktert jelenti) (szintén csak ASCII karaktereket találnak meg)
– elõre tekintés (lookahead): (?=), (?!) (negatív)
– hátra tekintés (lookbehin): (?<=), (?<!) (negatív)
o vezérlõ karakterek:
– (): gyûjtõ zárójel, a tartalma által megtalált szövegre 1, 2 stb. módon tudunk hivatkozni (ezeknél érdekes lehet, hogy így néz ki az oktális karakter megadási mód)
– |: csoportosítás (foo|bar)
– ?, *, +, {n,m}: számosság meghatározók (nulla vagy egy, nulla vagy több, egy vagy több, megadott számú találat, az intervalum bármelyik oldala lehet nyitott), ezek mohók (greedy), a lehetõ legtöbb karaktert próbálják meg elfogyasztani.
– ??, *?, +?, {n,m}?: lusta (lazy) számosság meghatározók (jelentés ugyanaz), viszont ezek a lehetõ legkevesebb karaktert próbálják meg elfogyasztani.
– ?+, *+, ++, {n,m}+: nem eresztõ (possessive) számosság meghatározók: ennek a backtracking mechanizmus miatt lesz jelentõsége, errõl majd lesz késõbb szó.
– (?:): nem gyûjtõ zárójel (hasznos lehet, hogy ha csak csoportosításra használnánk amúgy a zárójelet, akkor a “gyûjtés” miatti memória foglálás és adminisztráció felesleges)
– (?<Name>): nevesített capturing (a találatot ilyen néven keresztül fogjuk elérni, hasznos lehet, mert ez esetben nem függünk attól, hogy a regexbe bekerül esetleg még egy gyûjtõ zárójel)
– (?>): atomi grouping: szintén a backtracking mechanizmus miatt van jelentõsége
– (?(condition)yes-pattern), (?(condition)yes-pattern|no-pattern): feltételes egyezés vizsgálata, majd látunk rá példát
o módosítók:
– /…/xzy: a minta vége után felsorolhatjuk õket
– (?modifier): innentõl kezdve él a módosító ((?i) vagy (?-i) vagy kombinalva (?m-i))
– (?modifier:….): a zárójelen belül érvényes az adott módosító
– (?#…): komment
– #: komment (x módosító)
– Q…E: közöttük tetszõleges szöveg lehet, literálként lesz értelmezve
– módosítók:
o i: kis betû, nagy betû érzéketlen lesz a minta
o s: ilyenkor a . illeszkedik az újsor karakterre is
o m: ilyenkor a ^ és a $ csak a teljes szöveg elején illetve végén illeszkedik
o x: a whitespace karakterek nem lesznek részei a regexpnek (lesz rá példa)
o e: preg_replace esetén lesz érdekes, látunk rá példát
o u: UTF-8-ként lesz értelmezve a minta
o A, U, X, S, D

Általános jótanácsok:
o nem kötelezõ a / jelet használni határoló jelnek, lehet bármi más, a lényeg, hogy a regexpen belül escapleni kell.
$pattern = “!…!…!”;
o ha nem ismert tartalmú szöveget kell beilleszteni egy mintába, akkor használjuk a preg_quote parancsot (ha nem / jel a határoló, akkor meg kell adni a függvénynek).
$pattern = “!…”.preg_quote($_GET[‘search’], “!”).”…!”;
o használjunk nevesített capturinget, kevésbé hibaérzékeny.
o ha egy zárójel csak csoportosításra szolgál, akkor jelezzük, hogy nincs szükség a capturingre.
o a kicsit is bonyolultabb reguláris kifejezéseket kommentezzük, mintha sima programkód lenne, különben a késõbbiek során szintén elég nehezen módosíthatókká válnak.
/**
FAQ hozzaadasa egy kategoriahoz
@param int    $category_id    + Ebben a kategoriaban kell letrehozni a FAQ-ot
@param string $question       + FAQ-hoz tartozo kerdes
@param string $answer         + FAQ-hoz tartozo valasz
*/
public function actionAdd($category_id, $question, $answer) {
Controller_Faq::addItem($category_id, $question, $answer);
redirect(‘/faq/editor/ViewFaqs.cmd?category_id=’.$category_id);
}

function getActionParamsDefinition($pageClass, $action)
{
$reflection = new ReflectionClass($pageClass);
try {
$reflection = $reflection->getMethod(‘action’.$action);
} catch (ReflectionException $e) {
PEAR::raiseError(‘The requested action (‘.$action.’) not supported on this page!’);
}

if (null === ($comment = $reflection->getDocComment())) {
PEAR::raiseError(‘The requested action (‘.$pageClass.’->action’.$action.'()) has no DocComment!’);
};

// Nevesitett gyujto almintakat hasznlunk a konnyebb erthetoseg kedveert
$pattern = ‘
/# parameter informaciok kinyerese a kommentbol
@param                                             # kulcsszo megkereses
s+                                                # elvalasztas
(?P<type>int|string|array|boolean|float|number)    # lehetseges tipusok
s+                                                # elvalasztas
(?P<name>$[a-z_x7f-xff][a-z0-9_x7f-xff]*)     # parameter neve
s+                                                # elvalasztas
(?:                                                # leiras, ne gyujtse be a tartalmat
# kotelezo, opcionalis
(?:(?P<ismandatory>[+]))?                        # DEPRECATED egy darab plusz jel – mar nem hasznaljuk
# validatorok, opcionalis
(?:(                                          # nyito zarojel
(?P<validators>[a-z0-9_,]+)                # validatorok: szovegek vesszovel elvalasztva
))?                                           # zaro zarojel
.*?$                                           # leiras maradek resze
)
/imsx
‘;
// A $mataches tomb nulladik elemének mérete megadja a parameterek szamat.
preg_match_all($pattern, $comment, $commentParams);

Számosság:
o alap esetben ezek a módosítók mohók, a lehetõ legtöbb karaktert próbálják meg elfogyasztani:
$string = “…<a>1…</a>…<a>2…</a>….”;
$pattern = “/<a>.*</a>/”; // “<a>1…</a>…<a>2…</a>”
o ha ez számunkra nem jó, akkor hasznéljunk lusta módosítókat:
$string = “…<a>1…</a>…<a>2…</a>….”;
$pattern = “/<a>.*?</a>/”; // “<a>1…</a>”
o {n,m} forma esetén tetszõleges variácó létezik: {,m}, {n,}, {n,m}, {n}

Karakter osztályok:
o használhatunk POSIX kompatibilis megadási formát is: :alpha:, :alnum:, :ascii:, :cntrl:, :digit:, :graph:, :lower:, :print:, :space:, :upper:, :xdigit:. Ezeket lehet negálni is: :^alnum:. Például: [[:ascii:]], [[:^digit:]]
o [^]: a negált karakter osztályok minden karakterre illeszkednek, amelyik nincs benne az adott osztályban, még az újsorra is
$string = “<img …n…>”;
$pattern = “/<img.+?>/”;
$pattern = “/<img[^>]+>/”;

Módosítók:
o i: egyértelmû, szükség esetén használjuk.
o s: ha szeretnénk, hogy a . illeszkedjen minden karakterre, akkor kell használnunk.
$string = “<img …n…>”;
$pattern = “/<img.+?>/s”;
o m: ha szeretnénk, hogy a ^ és a $ ne csak a teljes szöveg elejére és végére illeszkedjen, akkor kell használnunk.
o S: ha gyakran futtatunk egy regexpet, akkor érdemes lehet kipróbálni ezt az opciót, ugyanis ezzel arra utasítjuk a PCRE motort, hogy elemezze jobban a regexpet, és optimálisabban hajtsa végre.
o u: példa email cím ellenõrzõ.
o e: ezzel azt érjük el preg_replace esetén, hogy a helyettesítendõ szöveg PHP kódként értékelõdik ki (majd látunk rá példát).

Egyszerûbb példák:
o IP cím ellenõrzése:
$matching255 = “(?#100 alatti szamok)[1-9]?[0-9]|(?#1xx)1[0-9]{2}|(?#200-249)2[0-4][0-9]|(?#25x)25[0-5]”;
preg_match(“/$matching255/”, “255”);

//25 (a csoportosítás elsõ eleménél ha találat van, akkor vége az illesztésnek)
preg_match(“/^$matching255$/”, “255”);

//25 (precedencia)
preg_match(“/^($matching255)$/”, “255”);
//255
$ipAddressPattern = “/^(($patternFor255).){3}($patternFor255)$/”;
o változónevek ellenõrzése:
$pattern = “/^$[a-z]+([A-Z][a-z]+)*$/”;
o szóismétlések megkeresése:
$pattern = “/b(w+)s+\1b/i”;
o email cím ellenõrzése:
$pattern = “/^[wd!#$%&’*+-/=?^`{|}~]+(.[wd!#$%&’*+-/=?^`{|}~]+)*@([a-zd][-a-zd]*[a-zd].)+[a-z][-a-zd]*[a-z]/i”;

Horgonyok:
o ahogy említettük, ezek nem fogyasztanak el karaktereket a szövegbõl, nulla hosszúságúak, segítségükkel különbözõ feltételek teljesülését tudjuk elõírni
o alap horgonyok: ^, $, A, Z, z, b
$_GET[“phone”] = “xxx30-123-1234xxx”;
preg_match(“/d{2}-d{3}-d{4}/”, $_GET[“phone”]); // TRUE
preg_match(“/^\d{2}-\d{3}-\d{4}$/”, $_GET[“phone”]); // FALSE

preg_match vs. preg_match_all
o a elõbbi az elsõ egyezést találja meg, a második az összeset.
o preg_match_all esetén hasznos lehet a PREG_SET_ORDER opció megadása: alap esetben a találatok tömbje elsõdlegesen a gyûjtõ zárójel sorszáma szerint van index-szelve, de ha megadjuk ezt az opciót, akkor a találatok sorendje lesz az elsõdleges index (a példa alapján ez érthetõ is lesz).
<?php
$subject = “….(1|2)….(2|3)…”;
$pattern = “/((d+)|(d+))/”;

preg_match($pattern, $subject, $match);
echo ‘<pre>’.htmlentities(print_r($match, true)).'</pre>’;
// Array
// (
//     [0] => (1|2)
//     [1] => 1
//     [2] => 2
// )

preg_match_all($pattern, $subject, $match);
echo ‘<pre>’.htmlentities(print_r($match, true)).'</pre>’;
// Array
// (
//     [0] => Array
//         (
//             [0] => (1|2)
//             [1] => (2|3)
//         )
//
//     [1] => Array
//         (
//             [0] => 1
//             [1] => 2
//         )
//
//     [2] => Array
//         (
//             [0] => 2
//             [1] => 3
//         )
//
// )

preg_match_all($pattern, $subject, $match, PREG_SET_ORDER);
echo ‘<pre>’.htmlentities(print_r($match, true)).'</pre>’;
// Array
// (
//     [0] => Array
//         (
//             [0] => (1|2)
//             [1] => 1
//             [2] => 2
//         )
//
//     [1] => Array
//         (
//             [0] => (2|3)
//             [1] => 2
//             [2] => 3
//         )
//
// )
foreach($match as $item) {}
?>

preg_replace:
o ftp, http, https URL-eket szeretnénk linkekre cserélni.
preg_replace(“!((ht|f)tps?://S+)!”, ‘<a href=”1″>1</a>’, $text);
o ugyanaz mint feljebb, de szeretnénk, hogy csak a ténylegesen létezõ URL-ekbõl legyen link, itt jön be a képbe az e módosító:
preg_replace(“!((ht|f)tps?://S+)!e”, ‘isExistentUrl(1) ? “<a href=”1″>1</a>” : “1 (dead link)”‘, $text);
o nagyon egyszerû template motor:
$string = “…{foo}…”;
$templateVars[“foo”] = “bar”;
preg_repalce(“/{(w+)}/e”, “$templateVars[1]”, $string);
o PHPMailer kiegészítése:

Backtracking:
o alap esetben az ilesztés folyamata:
$string = “foo12”;
$pattern = “/w+13/”;
// foo12   – illeszti az f-et
// [f]oo12 – illeszti az o-t
// [fo]o12 – illeszti a következõ o-t
// [foo]12 – illeszti az 1-est
// [foo1]2 – itt nem sikerül a 3-at illeszteni, ezért visszalép és felad egy karaktert
// [fo]o12 – itt nem sikerül az 1-et illeszteni, ezért visszalép és felad egy karaktert
// [f]oo12 – itt nem sikerül az 1-et illeszteni, ezért visszalép és felad egy karaktert
// foo12 – nem sikerült az ilesztés
o adott esetben mi tudhatjuk, hogy nincs értelme visszalépnie, és ezt jelezhetjük is, erre szolgálnak a nem eresztõ (possessive) számosság meghatározók.
$string = “foo12”;
$pattern = “/w++13/”;
// foo12   – illeszti az f-et
// [f]oo12 – illeszti az o-t
// [fo]o12 – illeszti a következõ o-t
// [foo]12 – illeszti az 1-est
// [foo1]2 – nem sikerült az illesztés
o ennek egyik alternatív megadási formája az atomic grouping:
$pattern = “/(?>w+)13/”;
o egy érdekes példa, csak hogy érzékeltessük ennek jelentõségét: legyen a feladatunk, hogy a wikire jelemzõ MindenSzoNagybetuvelKezdodik jellegû szavakat kell kigyûjteni. Az alap ötlet kapásból megvan:
$pattern = “/(([A-Z][a-z]+)+)/”;
Ha azonban van egy ilyen szövegünk: “JoHosszuFileNevAmiHasonlitArraAmitKeresunk.php”, akkor a backtracking miatt lényegesen meg tud nõni a kiértékelés ideje, amit lecsökkenthetünk (egy teszt szerint például 1,5 másodpercrõl 0,05-re), ha így adjuk meg a regexpet:
$pattern = “/(?>([A-Z][a-z]+)+)/”;

jozsi123
[j]ozsi123
[jo]zsi123
[joz]si123
[jozs]i123
[jozsi]123
[jozsi1]23
[jozsi12]3
jozsi123
[j]
|  marad   |  talalt  |
| jozsi123 |          |
|          |          |
|          |          |
|          |          |
|          |          |

SEO infok

Startup marketing: keresőoptimalizálás alapok

http://startupdate.hu/startup-marketing-keresooptimalizalas-alapok/

A keresőoptimalizálás (SEO) egy rendkívül hasznos marketing eszköz, hogy direkt költség felmerülése nélkül jelentős, releváns forgalmat terelhessünk weboldalunkra, akár kezdő vállalkozásként is. Startup marketing eszközök közül az egyik leghatásosabb megoldás.

*****

Mit mérhetünk a social médiában?

Schema.org provides a collection of shared vocabularies webmasters can use to mark up their pages in ways that can be understood by the major search engines: Google, Microsoft, and Yahoo!

http://schema.org/docs/gs.html

 

Kulcsszó választás okosan