2012-10-11 55 views
23

Estoy tratando de escribir expresiones regulares que extraiga todos los colores hexadecimales del código CSS.Regex para hacer coincidir los colores hexadecimales CSS

Esto es lo que tengo ahora:

Código:

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

Salida:

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

) 

No sé cómo especificar que sólo los colores se corresponden con los que termina puntuación, espacios en blanco o nueva línea.

+1

no se molestan con expresiones regulares. Ver la respuesta de @modu. 'if (ctype_xdigit ($ color) && strlen ($ color) == 6)'. –

Respuesta

31

Desde un código hexadecimal de color también puede constar de 3 caracteres, se puede definir un grupo obligatorios y un grupo opcional de letras y dígitos, por lo que la notación larga y elaborada sería:

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

O si lo desea una versión agradable y corta, puede decir que desea 1 o 2 grupos de 3 caracteres alfanuméricos, y que deben coincidir con mayúsculas y minúsculas (/i).

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

Gracias, \ b es lo que se necesitaba. No estoy seguro de por qué hay "?" aunque. De todos modos, esto funciona según sea necesario:/# (?: [0-9a-fA-F] {6}) \ b/ Olvidé mencionar que 3 códigos de caracteres no son necesarios. – Hemaulo

+0

Un signo de interrogación requiere cero o una ocurrencia de lo anterior, lo que hace que el segundo grupo capturado sea opcional. –

+2

Esas alternancias son inútiles. Aquí hay una versión más simple: '/ # ([a-fA-F0-9]) {3} (([a-fA-F0-9]) {3})? \ B /' – Synchro

0

No estoy del todo seguro de si tengo ese derecho, pero si sólo se desea hacer coincidir los colores hexagonales al final de una línea de CSS:

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

debería funcionar, lo único que hacía era agregue el grupo de caracteres opcional \s; (punto y coma y espacios opcionales) y un carácter de salto de línea (no opcional) y pareció funcionar.
Y como @GolezTrol señaló #FFF; es válido también.

Cuando se probó en esto:

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

La salida fue:

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

Shorter versión de GolezTrol's answer que evita la escritura establece el carácter doble:

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

Puede hacerlo incluso corto usando la bandera de coincidencia insensible a mayúsculas y minúsculas 'i'. '/ # ([a-f0-9] {3}) {1,2} \ b/i' – Tushar

6

Los espectáculos respuesta aceptada cómo hacerlo con expresiones regulares, porque esa era su pregunta. Pero realmente no necesita usar expresiones regulares para esto. Normalmente, esta es la forma en que lo haría:

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

de 100.000 iteraciones:

solución expresiones regulares *: 0.0802619457245 segundo

xdigit con strlen: 0.0277080535889 segundo

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

+0

¿Quién llamará a esta función 100,000 veces? – nbrogi

+3

Lo hice, solo para mostrarte qué método es más rápido. – modu

+0

Lo siento, pero este tipo de cosas son una locura. Esa función se llamará ¿qué, 5 veces como máximo en cualquier archivo PHP dado? Entonces, ¿estamos hablando de una fracción de milisegundo? – nbrogi

0

A pesar de la edad de esta pregunta, me gustaría enmendar lo siguiente:

^#([[:xdigit:]]{3}){1,2}$, donde [[:xdigit:]] es una abreviatura de [a-fA-F0-9].

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

Cuestiones relacionadas