Caracteres permitidos para identificadores CSS

¿Cuáles son los caracteres de juego (completos) válidos / permitidos para los identificadores de CSS id y class ?

¿Hay alguna expresión regular que pueda usar para validar? ¿Es navegador agnóstico?

El juego de caracteres no importa. Los personajes permitidos son más importantes. Verifique la especificación de CSS . Aquí hay una cita de relevancia:

En CSS, los identificadores (incluidos nombres de elementos, clases e ID en selectores ) pueden contener solo los caracteres [a-zA-Z0-9] e ISO 10646 caracteres U+00A1 y superiores, más el guión ( - ) y el guión bajo ( _ ); no pueden comenzar con un dígito, o un guión seguido de un dígito. Los identificadores también pueden contener caracteres escapados y cualquier carácter ISO 10646 como un código numérico (consulte el siguiente elemento). Por ejemplo, el identificador "B&W?" puede escribirse como "B\&W\?" o "B\26 W\3F" .

Actualización : en cuanto a la pregunta de expresión regular, puedes encontrar la gramática aquí :

 ident -?{nmstart}{nmchar}* 

Que contiene de las partes:

 nmstart [_a-z]|{nonascii}|{escape} nmchar [_a-z0-9-]|{nonascii}|{escape} nonascii [\240-\377] escape {unicode}|\\[^\r\n\f0-9a-f] unicode \\{h}{1,6}(\r\n|[ \t\r\n\f])? h [0-9a-f] 

Esto se puede traducir a una expresión regular de Java de la siguiente manera (solo agregué paréntesis a las partes que contenían el OR y escapé de las barras diagonales inversas):

 String h = "[0-9a-f]"; String unicode = "\\\\{h}{1,6}(\\r\\n|[ \\t\\r\\n\\f])?".replace("{h}", h); String escape = "({unicode}|\\\\[^\\r\\n\\f0-9a-f])".replace("{unicode}", unicode); String nonascii = "[\\240-\\377]"; String nmchar = "([_a-z0-9-]|{nonascii}|{escape})".replace("{nonascii}", nonascii).replace("{escape}", escape); String nmstart = "([_a-z]|{nonascii}|{escape})".replace("{nonascii}", nonascii).replace("{escape}", escape); String ident = "-?{nmstart}{nmchar}*".replace("{nmstart}", nmstart).replace("{nmchar}", nmchar); System.out.println(ident); // The full regex. 

Actualización 2 : oh, eres más un PHP’er, bueno, creo que puedes averiguar cómo / dónde hacer str_replace ?

Para cualquiera que busque algo un poco más llave en mano. La expresión completa, reemplazada y todo, de la respuesta de @ BalusC es:

 /-?([_a-z]|[\240-\377]|([0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|[^\r\n\f0-9a-f]))([_a-z0-9-]|[\240-\377]|([0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|[^\r\n\f0-9a-f]))*/ 

Y usando DEFINE , que me parece un poco más legible:

 /(?(DEFINE) (?P [0-9a-f] ) (?P (?&h){1,6}(\r\n|[ \t\r\n\f])? ) (?P ((?&unicode)|[^\r\n\f0-9a-f])* ) (?P [\240-\377] ) (?P ([_a-z0-9-]|(?&nonascii)|(?&escape)) ) (?P ([_a-z]|(?&nonascii)|(?&escape)) ) (?P -?(?&nmstart)(?&nmchar)* ) ) (?: (?&ident) )/x 

Dicho sea de paso, la expresión regular original (y la contribución de @humano) tenía unos pocos caracteres de escape falsos que permiten [ en el nombre.

Además, se debe tener en cuenta que la expresión regular sin, DEFINE , se ejecuta aproximadamente 2 veces más rápido que la expresión DEFINE , tomando solo ~ 23 pasos para identificar un único carácter Unicode, mientras que la última toma ~ 40.

Esto es simplemente una contribución a la respuesta @BalusC. Es la versión de PHP del código de Java que proporcionó, la convertí y pensé que otra persona podría encontrarla útil.

 $h = "[0-9a-f]"; $unicode = str_replace( "{h}", $h, "\{h}{1,6}(\r\n|[ \t\r\n\f])?" ); $escape = str_replace( "{unicode}", $unicode, "({unicode}|\[^\r\n\f0-9a-f])"); $nonascii = "[\240-\377]"; $nmchar = str_replace( array( "{nonascii}", "{escape}" ), array( $nonascii, $escape ), "([_a-z0-9-]|{nonascii}|{escape})"); $nmstart = str_replace( array( "{nonascii}", "{escape}" ), array( $nonascii, $escape ), "([_a-z]|{nonascii}|{escape})" ); $ident = str_replace( array( "{nmstart}", "{nmchar}" ), array( $nmstart, $nmchar ), "-?{nmstart}{nmchar}*"); echo $ident; // The full regex.