2012-10-11 15 views
23

Próbuję napisać wyrażenie regularne, które wyodrębnia wszystkie kolory szesnastkowe z kodu CSS.Regex dla pasujących kolorów sześciennych CSS

To co mam teraz:

Kod:

$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); 

wyjściowa:

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

) 

nie wiem jak określić, że tylko te kolory są dopasowywane który kończy interpunkcja, spacja lub znak nowej linii.

+1

Nie przejmuj się z regex. Zobacz odpowiedź @ modu. 'if (ctype_xdigit ($ color) && strlen ($ color) == 6)'. –

Odpowiedz

31

Ponieważ kod szesnastkowy koloru może również składać się z 3 znaków, można określić obowiązkową grupę i opcjonalnej grupa liter i cyfr, tak długa i skomplikowana notacja byłoby:

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

lub jeśli chcesz mieć ładną i krótką wersję, możesz powiedzieć, że chcesz 1 lub 2 grupy po 3 znaki alfanumeryczne, i że powinny one być dopasowane bez rozróżniania wielkości liter (/i).

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

Dzięki, \ b jest tym, co było potrzebne. Nie wiesz, dlaczego jest "?" chociaż. W każdym razie działa to w razie potrzeby:/# (?: [0-9a-fA-F] {6}) \ b/ Zapomniałem wspomnieć, że 3 kody nie są potrzebne. – Hemaulo

+0

Znak zapytania wymaga zera lub jednego wystąpienia poprzedniego, co powoduje, że druga przechwycona grupa jest opcjonalna. –

+2

Te zmiany są bezcelowe. Oto prostsza wersja: '/ # ([a-fA-F0-9]) {3} (([a-fA-F0-9]) {3})? \ B /' – Synchro

0

Nie jestem do końca pewien, czy mam to prawo, ale jeśli tylko chcą, aby dopasować kolory hex na końcu linii CSS:

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

powinny działać, wszystko zrobiłem było dodaj opcjonalną grupę znaków \s; (opcjonalnie średnik i spacje) i znak końca linii (nie opcjonalny) i wydawało się, że działa.
I jak @GolezTrol zwrócił uwagę, że #FFF; jest również ważny.

Podczas badania na ten temat:

$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); 

Wyjście było:

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

Krótsza wersja GolezTrol's answer że unika pisania zestaw znaków dwukrotnie:

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

Możesz to uczynić jeszcze krótszym, używając flagi "i" niewrażliwe na wielkość liter. '/ # ([a-f0-9] {3}) {1,2} \ b/i' – Tushar

6

przyjętym pokazy odpowiedź jak to zrobić z regex, ponieważ to było twoje pytanie. Ale naprawdę nie musisz używać do tego celu regex. Zazwyczaj jest to w jaki sposób to zrobić:

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

do 100.000 powtórzeń:

Regex rozwiązanie *: 0.0802619457245 sekund

xdigit z strlen: 0.0277080535889 sekund

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

+0

Kto będzie nazywał tę funkcję 100 000 razy? – nbrogi

+3

Zrobiłem, żeby pokazać, która metoda jest szybsza. – modu

+0

Przepraszam, ale takie rzeczy są szalone. Ta funkcja będzie nazywać się, co najwyżej 5 razy w dowolnym pliku PHP? Więc mówimy o ułamku milisekundy? – nbrogi

0

Pomimo tego wieku pytanie chciałbym dodać następujące informacje:

^#([[:xdigit:]]{3}){1,2}$, gdzie [[:xdigit:]] jest skrótem dla [a-fA-F0-9].

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