2012-10-11 12 views
23

Ich versuche, Regex zu schreiben, die alle Hex-Farben aus dem CSS-Code extrahiert.Regex für passende CSS Hex Farben

Das ist, was ich habe jetzt:

Code:

$css = <<<CSS 

/* Do not match me: #abcdefgh; I am longer than needed. */ 

.foo 
{ 
    color: #cccaaa; background-color:#ababab; 
} 

#bar 
{ 
    background-color:#123456 
} 
CSS; 

preg_match_all('/#(?:[0-9a-fA-F]{6})/', $css, $matches); 

Ausgang:

Array 
(
    [0] => Array 
     (
      [0] => #abcdef 
      [1] => #cccaaa 
      [2] => #ababab 
      [3] => #123456 
     ) 

) 

Ich weiß nicht, wie nur angeben, dass diese Farben abgestimmt sind, welche Enden mit Interpunktion, Leerzeichen oder Zeilenumbruch.

+1

Kümmern Sie sich nicht mit Regex. Siehe @ modus Antwort. 'if (ctype_xdigit ($ color) && strlen ($ color) == 6)'. –

Antwort

31

Da ein Hex-Farbcode auch 3 Zeichen bestehen kann, können Sie eine verbindliche Gruppe und eine optionale Gruppe von Buchstaben und Ziffern definieren, so würde die lange und aufwendige Notation sein:

/#([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?\b/ 

Oder wenn Sie Wenn Sie eine nette und kurze Version wünschen, können Sie sagen, dass Sie entweder 1 oder 2 Gruppen mit je 3 alphanumerischen Zeichen haben möchten und dass diese ohne Groß- und Kleinschreibung angepasst werden sollen (/i).

/#([a-f0-9]{3}){1,2}\b/i 
+0

Danke, \ b ist was benötigt wurde. Nicht sicher, warum es "?" obwohl. Wie auch immer, dies funktioniert wie benötigt:/# (?: [0-9a-fA-F] {6}) \ b/ Vergessen zu erwähnen, dass 3 Zeichencodes nicht benötigt wird. – Hemaulo

+0

Ein Fragezeichen erfordert null oder ein Vorkommen des Vorhergehenden, wodurch die zweite erfasste Gruppe optional wird. –

+2

Diese Wechsel sind sinnlos. Hier ist eine einfachere Version: '/ # ([a-fA-F0-9]) {3} (([a-fA-F0-9]) {3})? \ B /' – Synchro

0

Ich bin nicht ganz sicher, ob ich dieses Recht hätte, aber wenn man nur Hex-Farben am Ende einer CSS-Linie übereinstimmen soll: arbeiten

preg_match_all('/#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})[\s;]*\n/',$css,$matches); 

soll, alles, was ich tat, war, Fügen Sie die optionale \s; Char-Gruppe (optional Semikolon und Leerzeichen) und ein Zeilenumbruchzeichen (nicht optional) hinzu und es schien zu funktionieren.
Und wie @GolezTrol darauf hingewiesen #FFF; ist auch gültig.

Wenn auf diese getestet:

$css = '/* Do not match me: #abcdefgh; I am longer than needed. */ 
.foo 
{ 
    color: #CAB; 
    background-color:#ababab; 
}'; 
preg_match_all('/#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})[\s;]*\n/',$css,$matches); 
var_dump($matches); 

Der Ausgang war:

array (array('#CAB;','#ababab;')) 
19

Kürzere Version von GolezTrol's answer, die das Zeichen zweimal eingestellt vermeidet Schreiben:

/#([a-fA-F0-9]{3}){1,2}\b/ 
+2

Sie können es sogar kurz machen, indem Sie das i-Zeichen ohne Beachtung der Groß-/Kleinschreibung verwenden. '/ # ([a-f0-9] {3}) {1,2} \ b/i' – Tushar

6

Die akzeptierte Antwort zeigt Sie, wie Sie es mit Regex tun, denn das war Ihre Frage. Aber Sie brauchen dafür keine Regex zu verwenden. Normalerweise ist dies, wie ich es tun würde:

if(ctype_xdigit($color) && strlen($color)==6){ 
    // yay, it's a hex color! 
} 

für 100.000 Iterationen:

Regex Lösung *: 0,0802619457245 Sekunden

xdigit mit strlen: 0,0277080535889 Sekunden

*: hex: ([a-fA-F0-9]{6})

+0

Wer wird diese Funktion 100.000 Mal aufrufen? – nbrogi

+3

Ich tat, nur um Ihnen zu zeigen, welche Methode schneller ist. – modu

+0

Sorry, aber diese Art von Dingen sind verrückt. Diese Funktion wird in jeder gegebenen PHP-Datei höchstens 5-mal aufgerufen? Wir sprechen also von einem Bruchteil einer Millisekunde? – nbrogi

0

Trotz des Alters dieser Frage möchte ich Folgendes ändern:

^#([[:xdigit:]]{3}){1,2}$, wobei [[:xdigit:]] eine Kurzschrift für [a-fA-F0-9] ist.

So:
<?php preg_match_all("/^#([[:xdigit:]]{3}){1,2}$/", $css, $matches) ?>