Hoy, su tarea es escribir un programa (o una función) que acepte una cadena y genere (o devuelva) cuatro enteros.
Entrada
La cadena de entrada es un selector CSS3 y puede contener básicamente cualquier carácter Unicode.
Salida
La salida representa la especificidad CSS de este selector.
El primer número siempre es 0 (porque se usa para estilos en línea, y este ejercicio no se aplica a los estilos en línea)
El segundo número es el número de identificadores (
#foo
) presentes en el selector.El tercer número es el número de clases (
.foo
), atributos ([bar]
) y pseudo-clases presentes en el selector.El cuarto número es el número de elementos (
biz
) y pseudoelementos presentes en el selector.
Notas:
El selector universal (*) no se cuenta en ninguna parte
Los pseudo-elementos
::before
y::after
también se pueden escribir con un solo ":" (notación heredada)La entrada puede usar la
:not(selector)
pseudoclase. El selector interno no cuenta, incluso si contiene identificadores, clases, elementos, ...)Los "ladrillos" del selector están separados por combinadores (espacios / pestañas,
+
,>
,~
, ex:body > div+a ~*
), pero también pueden acumularse (ex:div#foo.bar[baz]:hover::before
)También debe manejar secuencias de escape CSS (
\
seguidas de 1 a 6 números hexadecimales, seguidos de un espacio) y caracteres especiales escapados (\
seguidos de cualquiera de estos!"#$%&'()*+,-./:;<=>?@[\]^`{|}~
:) correctamente. Esos escapes pueden ser parte de cualquier ladrillo del selector (id, clase, etc.).No necesita hacer nada en particular si recibe un selector no válido o un selector CSS4. No te molestes en implementar un validador selector CSS3.
Aquí hay algunos enlaces para aprender más sobre CSS específicamente:
- Artículo de trucos CSS: http://css-tricks.com/specifics-on-css-specificity/
- Una herramienta (incompleta) que lo cuenta: http://specificity.keegan.st/
Ejemplos
// Universal * => 0,0,0,0 // CARNÉ DE IDENTIDAD #id => 0,1,0,0 // Clase .class => 0,0,1,0 // Atributos [foo] => 0,0,1,0 [foo = "bar"] => 0,0,1,0 [foo ~ = "bar"] => 0,0,1,0 [foo ^ = "bar"] => 0,0,1,0 [foo $ = "bar"] => 0,0,1,0 [foo * = "bar"] => 0,0,1,0 [foo | = "bar"] => 0,0,1,0 [foo = bar] => 0,0,1,0 [foo = 'bar'] => 0,0,1,0 (Nota: los corchetes [] pueden contener cualquier cosa excepto un "]" sin escape) // Pseudo-clases : raíz => 0,0,1,0 : enésimo hijo (n) => 0,0,1,0 : nth-last-child (n) => 0,0,1,0 : enésimo tipo (n) => 0,0,1,0 : enésimo último tipo (n) => 0,0,1,0 : primer hijo => 0,0,1,0 : último hijo => 0,0,1,0 : primero de tipo => 0,0,1,0 : último tipo => 0,0,1,0 : only-child => 0,0,1,0 : solo de tipo => 0,0,1,0 : vacío => 0,0,1,0 : enlace => 0,0,1,0 : visitado => 0,0,1,0 : activo => 0,0,1,0 : hover => 0,0,1,0 : foco => 0,0,1,0 : objetivo => 0,0,1,0 : lang (fr) => 0,0,1,0 : habilitado => 0,0,1,0 : deshabilitado => 0,0,1,0 : verificado => 0,0,1,0 : no (selector) => 0,0,1,0 (Nota: la palabra clave después de ":" puede ser cualquier cosa menos un pseudo-elemento) // Elementos cuerpo => 0,0,0,1 // Pseudoelementos : antes => 0,0,0,1 : después => 0,0,0,1 :: antes => 0,0,0,1 :: después => 0,0,0,1 :: primera línea => 0,0,0,1 :: primera letra => 0,0,0,1 (Nota: el paréntesis () puede contener cualquier cosa excepto un ")" sin escape)
(continuará)
Si tiene preguntas o necesita ejemplos o datos de prueba, pregunte en los comentarios.
El código más corto (en bytes) gana.
¡Buena suerte!
1
sería genial. (Por cierto, creo que este es realmente un desafío bastante bueno, pero una lista exhaustiva de casos de prueba parece vital para que funcione bien.)