/ Forside / Teknologi / Udvikling / PHP / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
PHP
#NavnPoint
rfh 3959
natmaden 3372
poul_from 3310
funbreak 2700
stone47 2230
Jin2k 1960
Angband 1743
Bjerner 1249
refi 1185
10  Interkril.. 1146
noget med range()
Fra : scootergrisen


Dato : 30-11-10 08:30

Jeg har en funktion som tester stelnumre.
Ud fra det først tegn kan man se hvilken kontinent køretøjet fra.

Hvis det første tegn er a, b, c, d, e, f, g eller h så er den fra afrika
og jeg skriver sådan her:

$database['afrika'] = array(range('a', 'h'));
$database['asien'] = array(range('j', 'r'));
$database['europa'] = array(range('s', 'z'));
$database['nord amerika'] = array(range('1', '5'));
$database['oceanien'] = array(range('6', '7'));
$database['syd amerika'] = array(range('8', '9'));

Det virker fint.

Men nu vil jeg gerne teste det næste tegn i stelnummeret som fortæller
hvilket lang køretøjet er fra.

For kina vil jeg gerne lave et array som skal indenholde:
a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 0

Det kan jeg så lave med:
array_merge(range('a', 'z'), range('1', '9'), array(0))

Men er der ikke en smartere måde jeg kan skrive det på i stedet for at
skulle bruge array_merge() ?

Måske at jeg kan lave en hjemmelavet min_range() som forstår at når jeg
skrive min_range('a', '0') så bliver det til:
a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 0

Men jeg vil også gerne kunne skrive min_range('6', '0') også der bliver:
6 7 8 9 0

Hvad syns i ville være smart at gøre ?

 
 
Martin Larsen (30-11-2010)
Kommentar
Fra : Martin Larsen


Dato : 30-11-10 10:35

scootergrisen wrote:

> Hvad syns i ville være smart at gøre ?

Brug regulære udtryk. Så kan du teste op mod udtryk som [a-z0-9] hvilket
giver dig det ønskede område.

Hvis jeg skal lave et eksempel til dig, så kom med et stelnummer der
skal testes plus hvad jeg ellers skal vide.

Martin

scootergrisen (30-11-2010)
Kommentar
Fra : scootergrisen


Dato : 30-11-10 11:31

> Brug regulære udtryk. Så kan du teste op mod udtryk som [a-z0-9] hvilket
> giver dig det ønskede område.
>
> Hvis jeg skal lave et eksempel til dig, så kom med et stelnummer der
> skal testes plus hvad jeg ellers skal vide.

Det er de 2 først tegn i stelnummeret jeg skal teste.
Det kan for eksempel være LV
Men jeg kan ikke bruge a-z0-9 fordi landekoderne ikke er lavet fra 0-9
de er lavet som a-z også 1 2 3 4 5 6 7 8 9 0

Her er nogle landekoder :
JA-J0 Japan
KA-KE Sri Lanka
KF-KK Israel
KL-KR Korea (South)
KS-K0 not assigned
LA-L0 China
MA-ME India

Så hvis stelnummer starter med LV er den fra kina.

Lad og sige stelnummeret startede med KC hvordan skulle jeg så teste med
regulært udtryk ?

Og kan jeg bruge a-z 1-9 0 i en range() ?

Martin Larsen (30-11-2010)
Kommentar
Fra : Martin Larsen


Dato : 30-11-10 12:27

scootergrisen wrote:

> Men jeg kan ikke bruge a-z0-9 fordi landekoderne ikke er lavet fra 0-9
> de er lavet som a-z også 1 2 3 4 5 6 7 8 9 0

Det er ligegyldigt for regex. A-Z0-9 vil virke fint.

> Lad og sige stelnummeret startede med KC hvordan skulle jeg så teste med
> regulært udtryk ?

<?
$stelNrRegEx = <<<EOD
(?P<japan>J[A-Z0-9])|
(?P<srilanka>K[A-C])|
(?P<israel>K[F-K])|
(?P<sydkorea>K[L-R])|
(?P<ukendt>K[S-Z0-9])|
(?P<kina>L[A-Z0-9])|
(?P<indien>M[A-E])
EOD;

function TestStelnummer($stelnummer) {
global $stelNrRegEx;
preg_match("%$stelNrRegEx%x", $stelnummer, $match);
foreach($match as $key=>$value) {
if(!is_numeric($key) && $value!=='') {
return $key;
}
}
}

echo TestStelnummer('LV'),"\n";
echo TestStelnummer('KC'),"\n";
echo TestStelnummer('MB'),"\n";
?>

Som du ser kan se kan du let opstille reglerne skematisk. Konstruktionen
(?P<navn>) er navngivne regulære udtryk som gør det lettere at have med
at gøre.

<<<EOD er en heredoc-konstruktion. Du kan også bare skrive det ud i én
køre: $stelNrRegEx = '(?P<japan>J[A-Z0-9])|(?P<srilanka>K[A-C])....' men
det bliver hurtigt en lang linje!

Udtrykkene læses sådan her, fx for Indien: Et M efterfulgt af
bogstaverne A-E.


Regex er nyttige præcis til sådanne opgaver fordi der kan opstilles
*regler* for hvad der skal matches. Regulære udtryk burde snarere hedde
Regelrette udtryk fordi regulært i daglig tale betyder noget helt andet.
Så hvis der kan opstilles regler, er regex værd at overveje.

Martin


Martin Larsen (30-11-2010)
Kommentar
Fra : Martin Larsen


Dato : 30-11-10 12:30

Skal lige tilføje at jeg her tester for landene, det kan let udvides med
kontinentet også.


scootergrisen (30-11-2010)
Kommentar
Fra : scootergrisen


Dato : 30-11-10 13:15

Tak jeg prøver og kigge på koden.

>> Men jeg kan ikke bruge a-z0-9 fordi landekoderne ikke er lavet fra 0-9
>> de er lavet som a-z også 1 2 3 4 5 6 7 8 9 0
>
> Det er ligegyldigt for regex. A-Z0-9 vil virke fint.

Ja men det er ikke ligegyldigt hvad rækkefælge det er i iforhold til at
finde ud af hvad land køretøjet er lavet i.

Fordi 3 4 5 kan betyde kroatien og 6 7 8 9 0 er estonia.

V3-V5 Croatia
V6-V0 Estonia


Martin Larsen (30-11-2010)
Kommentar
Fra : Martin Larsen


Dato : 30-11-10 13:24

scootergrisen wrote:
> Ja men det er ikke ligegyldigt hvad rækkefælge det er i iforhold til at
> finde ud af hvad land køretøjet er lavet i.
>
> Fordi 3 4 5 kan betyde kroatien og 6 7 8 9 0 er estonia.

OK, men det gør du bare sådan her: [3-5] for Kroatien og [06-9] for
Estonia. Eller [6-90] men det ser ud som om det er mellem 6 og 90,
hvilket det jo ikke. Men PHP har det fint med det.

Du kan også skrive det helt ud hvis det er mere overskueligt: [67890]

scootergrisen (01-12-2010)
Kommentar
Fra : scootergrisen


Dato : 01-12-10 08:31

Tak det ser ud til at virke rigtig godt.

Men hvordan laver jeg mellemrum så :

(?P<srilanka>K[A-C])|

Bliver til :

(?P<sri lanka>K[A-C])|

Det virker så bare ik det sidste.
Så læste jeg noget med \s men det syns jeg heller ikke virker.

Martin Larsen (01-12-2010)
Kommentar
Fra : Martin Larsen


Dato : 01-12-10 10:15

scootergrisen wrote:

> Men hvordan laver jeg mellemrum så :
>
> (?P<srilanka>K[A-C])|
>
> Bliver til :
>
> (?P<sri lanka>K[A-C])|

Det er vist ikke muligt med mellemrum. Men så bruger du bare fx
sri_lanka og erstatter underscore med mellemrum.

scootergrisen (02-12-2010)
Kommentar
Fra : scootergrisen


Dato : 02-12-10 03:29

Hvordan får jeg det til at virke med æøå ?

Hvis jeg bruger ø retuner preg_match false.

'|(?P<østrig>v[a-e])'

Martin Larsen (02-12-2010)
Kommentar
Fra : Martin Larsen


Dato : 02-12-10 10:12

scootergrisen wrote:

> '|(?P<østrig>v[a-e])'

Hvis du mixer store og små bogstaver skal du bruge i (ignore case)
parameteren i de regulære udtryk:

preg_match("%$stelNrRegEx%xi", $stelnummer, $match);

Bemærk xi i stedet for før x.

> Hvordan får jeg det til at virke med æøå ?

Du kan ikke bruge æøå. Brug oestrig. Så erstatter du oe med ø bagefter.
Du kan erstatte alle tingene på en gang:

I stedet for

return $key;

bruger du

return str_replace(array('_', 'oe', 'aa'), array(' ', 'ø', 'å'), $key);

Det erstatter _, oe og aa med hhv. mellemrum, ø og å. Det er med vilje
at jeg har sprunget ae over da israel ellers vil blive til isræl! Og jeg
mener ikke der findes lande med æ.


Men der er et alternativ. Du kan undlade at bruge navngivne udtryk og i
stedet skrive landenavnene som en kommentar på hver linje. Så er der
frit slag med stavemåden og mellemrum osv. Ligesom i PHP ignores alt
efter # på en linje (når man bruger x parametren), så det regulære
udtryk kan så skrives:

(J[A-Z0-9])|#japan
(K[A-C])|#sri lanka
(K[F-K])|#israel
(K[L-R])|#sydkorea
(K[S-Z0-9])|#ukendt
(L[A-Z0-9])|#kina
(M[A-E])|#indien
(V[A-E])#østrig

I første omgang gør det ingen forskel da alt efter # som sagt ignoreres.
Men tricket er så at oprette et array ud fra oplysningerne i udtrykket:

$lande = explode("\n", preg_replace('%^\([^#]+#%m', '', $stelNrRegEx));

Nu har vi altså landene i et array.

Tilbage er så bare slå op i landetabellen. Det er sådan at hvis der ikke
bruges navngivne udtryk, så nummeres de enkelte matches fortløbende så
match1=japen, match2=sri lanka osv.

Altså:

return $lande[$key-1];

Her får du hele molevitten i køreklar tilstand:

<?
$stelNrRegEx = <<<EOD
(J[A-Z0-9])|#japan
(K[A-C])|#sri lanka
(K[F-K])|#israel
(K[L-R])|#sydkorea
(K[S-Z0-9])|#ukendt
(L[A-Z0-9])|#kina
(M[A-E])|#indien
(V[A-E])#østrig
EOD;

$lande = explode("\n", preg_replace('%^\([^#]+#%m', '', $stelNrRegEx));
//$lande = explode(',', 'japan,sri
lanka,israel,sydkorea,ukendt,kina,indien,østrig');
//$lande = array('japan','sri lanka');

function TestStelnummer($stelnummer) {
global $stelNrRegEx, $lande;
preg_match("%$stelNrRegEx%xi", $stelnummer, $match);
foreach($match as $key=>$value) {
if($key>0 && $value!=='') {
return $lande[$key-1];
}
}
}

echo TestStelnummer('LV'),"\n";
echo TestStelnummer('KC'),"\n";
echo TestStelnummer('MB'),"\n";
echo TestStelnummer('KK'),"\n";
echo TestStelnummer('VB'),"\n";
?>

scootergrisen (02-12-2010)
Kommentar
Fra : scootergrisen


Dato : 02-12-10 11:55

Tak igen.
Det lader til jeg kunne have brug for at læse noget om regulært udtryk
men jeg fatter bare ikk en skid af det.
De gange jeg har prøvet at bruge det har jeg hele tiden måtte gætte mig
frem.

Jeg kan godt se det kan ik masse smart men det bare svært at forstå det.

Men tak i hvert fald jeg tror bare jeg skal have noget tid til at forstå
det bedre.

Martin Larsen (02-12-2010)
Kommentar
Fra : Martin Larsen


Dato : 02-12-10 12:18

scootergrisen wrote:

> Men tak i hvert fald jeg tror bare jeg skal have noget tid til at forstå
> det bedre.

Du har ret i at det kan være svært at forstå. Faktisk kan det virke som
sort snak indtil man fatter det, men det er utroligt kraftfuld og
fleksibelt, og man kan ofte gøre tingene med ganske få linjer.

Men dog er de grundlæggende ting egentligt ikke så svære.

Lad os tage et par eksempler:

(J[A-Z0-9])|#japan

Som nævnt før så ignoreres det efter nummertegnet, så vi har altså:

(J[A-Z0-9])|

Den lodrette streg betyder "eller", dvs. vi matcher denne linje eller
det der kommer på den næste linje.

Ofte skriver man udtrykket på en lang linje, men er det langt,
foretrækker jeg at dele det op som gjort her.

Alternativt kun man skrive: (J[A-Z0-9])|(K[A-C])|(K[F-K]) ....

men som du nok kan se, så mister man hurtigt overblikket.


Nå, men vi har nu for japan (uden eller-tegnet):

(J[A-Z0-9])

Når man læser regex er det en god ide at sige "efterfulgt af". Dvs. her
et J efterfulgt af bogstaverne A-Z eller tallene 0-9. Det som er inde i
klammer [] er karaktersæt, og her kan man benytte ranges/intervaller.
Der matches hvis blot et af tegnene matcher.

Som du ser er udtrykket inde i en parantes. Det er for at "fange"
resultatet så vi kan bruge det senere. Den første parantes er 1 (her
japan), den næste 2 (sri lanka) osv. Hvis deludtrykkene navngives, kan
man også tilgå dem ved at bruge deres navne. Der som du selv har
opdaget, ikke må indeholde danske bogstaver og mellemrum etc.

Når man angiver det regulære udtryk i fx preg_match() så skal det
afgrænses af et sæt tegn man selv vælger. Det skal bare være et tegn der
ikke findes i udtrykket. Ofte bruger man / men jeg kan bedre lide %
fordi det så sjældent bruges.

preg_match("%$stelNrRegEx%xi", $stelnummer, $match);

Her er selve udtrykket altså indeholdt i $stelNrRegEx, og det er
afgrænset af et sæt procenttegn. Derefter følger to såkaldte "modifiers"
(eller parametre om man vil) nemlig x og i. x tillader den udvidede
syntax med fx kommentarer, og i betyder ignore case.

De enkelte resultater vil så ligge i arrayet match, altså match[1]=japan
osv.

Linjen som opretter lande-arrayet er ret kompliceret:

$lande = explode("\n", preg_replace('%^\([^#]+#%m', '', $stelNrRegEx));

Jeg vil ikke trætte dig med en forklaring, blot sige at man også bare
kan oprette det manuelt, som det også er vist i koden udkommenteret:

$lande = array('japan','sri lanka' ...);

Her er et godt site om regex: http://www.regular-expressions.info/

Og denne bog er fremragende: http://regex.info/


scootergrisen (02-12-2010)
Kommentar
Fra : scootergrisen


Dato : 02-12-10 13:25

Tak for forklaringen.
Tror bare jeg skal bruge regulært udtryk i min kode nogen flere gange
for at forstå lidt af gange.
Jeg bruger det på min hjemmeside til at hente noget data og det virker
men det har været gæt meget af det indtil det virkede.

Hvis jeg har :
'noget tekst', '', ''
'mere tekst', '', ''

og gerne vil have :
'noget tekst', '', '', ''
'mere tekst', '', '', ''

Hvordan gør man så ?

Martin Larsen (02-12-2010)
Kommentar
Fra : Martin Larsen


Dato : 02-12-10 13:34

scootergrisen wrote:

> og gerne vil have :
> 'noget tekst', '', '', ''
> 'mere tekst', '', '', ''
>
> Hvordan gør man så ?

Hmmm, jeg forstår ikke spørgsmålet

scootergrisen (04-12-2010)
Kommentar
Fra : scootergrisen


Dato : 04-12-10 12:14

> Hmmm, jeg forstår ikke spørgsmålet

Det svært og forklare men det også ligemeget.
Men tak for det andet.

scootergrisen (30-11-2010)
Kommentar
Fra : scootergrisen


Dato : 30-11-10 12:11

Jeg har lavet dette array : http://scootergrisen.dk/test/test0010.html
Men gjorde da ikke noget hvis det kunne laves smartere.


Søg
Reklame
Statistik
Spørgsmål : 177579
Tips : 31968
Nyheder : 719565
Indlæg : 6409073
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste