2008-12-12 11 views
5
Regex.IsMatch("foo", "[\U00010000-\U0010FFFF]") 

Throws: System.ArgumentException: análisis "[-]" - [x-y] rango en orden inverso.C# Expresiones regulares con caracteres Uxxxxxxxx en el patrón

Al mirar los valores hexadecimales para \ U00010000 y \ U0010FFF obtengo: 0xd800 0xdc00 para el primer carácter y 0xdbff 0xdfff para el segundo.

Así que supongo que realmente tengo un problema. ¿Por qué los caracteres Unicode formados con \ U se dividen en dos caracteres en la cadena?

Respuesta

9

Son surrogate pairs. Mire los valores - son más de 65535. Un char es solo un valor de 16 bits. ¿Cómo expresaría 65536 en solo 16 bits?

Desafortunadamente, no está claro en la documentación cómo (o si) el motor de expresiones regulares en .NET resuelve los caracteres que no están en el plano multilingüe básico. (El patrón \ uxxxx en la documentación de expresiones regulares solo cubre 0-65535, al igual que \ uxxxx como una secuencia de escape C#)

¿Es su expresión regular real más grande o simplemente está tratando de ver si hay alguna no BMP caracteres allí?

+0

En realidad, tienes razón. Por lo que he encontrado, \ u solo admite 4 dígitos hexadecimales (exactamente 4, no más, no menos), \ uFFFF es el máximo. He eliminado mi "solución" porque, aunque no produce un error, no parece ser una expresión regular de Unicode válida. Sigo creyendo que el \ necesita ser escapado. –

+0

Sin @, necesitaría escapar \ if \ UFFFF para la sintaxis de expresiones regulares (como \ d para [0-9]), pero en su lugar es una sintaxis literal de cadenas (como \ n para el carácter de nueva línea). –

+0

Esto es desafortunado: muchos emojis modernos se incluyen en esta categoría. – damian

1

@ Jon Skeet

Así que lo que me está diciendo es que no hay una manera de utilizar las herramientas de expresiones regulares de .NET para que coincida con el caracteres fuera del rango de UTF-16?

La expresión regular completa es:

^(\u0009|[\u0020-\u007E]|\u0085|[\u00A0-\uD7FF]|[\uE000-\uFFFD]|[\U00010000-\U0010FFFF])+$ 

que estoy tratando de comprobar si una cadena contiene solamente lo que es un documento yaml define como chararters Unicode imprimibles.

+0

No lo sé, desafortunadamente. No puedo ver nada en la documentación sobre cómo usar el motor de expresiones regulares .NET con caracteres fuera del plano multilingüe básico. Sin embargo, probablemente no sea demasiado difícil implementar lo que desee sin usar expresiones regulares en absoluto. –

+1

Alternativamente, podría usar los puntos de código de 16 bits que conforman los pares de sustitución: [\ ud800- \ udfff].Al menos vale la pena intentarlo ... –

+0

(Y en ese punto, puedes combinar varios de tus rangos juntos - los últimos bits son solo [\ u00a0- \ ufffd].) –

3

Para solucionar este tipo de cosas con motor de expresiones regulares .Net, estoy usando siguiente truco: "[\U010000-\U10FFFF]" se sustituye con [\uD800-\uDBFF][\uDC00-\uDFFF] La idea detrás de esto es que como expresiones regulares .Net manejan unidades de código en lugar de puntos de código, estamos proporcionando con rangos sustitutos como personajes regulares. También es posible especificar rangos más estrechos operando con bordes, por ejemplo: [\U011DEF-\U013E07] es lo mismo que (?:\uD807[\uDDEF-\uDFFF])|(?:[\uD808-\uD80E][\uDC00-\uDFFF])|(?:\uD80F[\uDC00-uDE07])

Es más difícil de leer y operar, y no es tan flexible, pero aún se adapta como solución alternativa.

Cuestiones relacionadas