Rango de caracteres UTF-8 en C++11 Regex


Esta pregunta es una extensión de ¿Funcionan las expresiones regulares de C++11 con cadenas UTF-8?

#include <regex>  
if (std::regex_match ("中", std::regex("中") ))  // "\u4e2d" also works
  std::cout << "matched\n";

El programa se compila en Mac Mountain Lion con clang++ con las siguientes opciones:

clang++ -std=c++0x -stdlib=libc++

El código anterior funciona. Este es un regex de rango estándar "[一-龠々〆ヵヶ]" para hacer coincidir cualquier Kanji japonés o carácter chino. Funciona en Javascript y Ruby, pero parece que no puedo obtener rangos que funcionen en C++11, incluso con el uso de una versión similar [\u4E00-\u9fa0]. El siguiente código no coincide cadena.

if (std::regex_match ("中", std::regex("[一-龠々〆ヵヶ]")))
  std::cout << "range matched\n";

Cambiar la configuración regional tampoco ha ayudado. Alguna idea?

EDITAR

Así que he encontrado que todos los rangos funcionan si agregas un + al final. En este caso [一-龠々〆ヵヶ]+, pero si se añade {1} [一-龠々〆ヵヶ]{1} no funciona. Además, parece sobrepasar sus límites. No coincidirá con caracteres latinos, pero coincidirá con que es \u306f y que es \u3041. Ambos se encuentran debajo \u4E00

Nhahtdh también sugirió regex_search, que también funciona sin agregar + pero todavía se encuentra con el mismo problema que el anterior al extraer valores fuera de su rango. Jugó con los locales un poco también. Mark Ransom sugiere que trata la cadena UTF-8 como un tonto conjunto de bytes, creo que esto es posiblemente lo que está haciendo.

Empujando aún más la teoría de que UTF-8 se está mezclando de alguna manera, [a-z]{1} y [a-z]+ coincide con a, pero solo [一-龠々〆ヵヶ]+ coincide con cualquiera de los caracteres, no [一-龠々〆ヵヶ]{1}.

Author: Community, 2013-04-08

1 answers

Codificada en UTF-8, la cadena "[一-龠々〆ヵヶ]" es igual a esta: "[\xe4\xb8\x80-\xe9\xbe\xa0\xe3\x80\x85\xe3\x80\x86\xe3\x83\xb5\xe3\x83\xb6]". Y esta no es la clase de caracteres droid que estás buscando.

La clase de caracteres que está buscando es la que incluye:{[19]]}

  • cualquier carácter en el rango U+4E00..U + 9FA0; o
  • cualquiera de los caracteres 々, any,.,..

La clase de caracteres que especificó es la que incluye:{[19]]}

  • cualquiera de los" caracteres " \xe4 o \xb8; o
  • cualquiera "carácter" en el rango \x80..\xe9; o
  • cualquiera de los "caracteres" \xbe, \xa0, \xe3, \x80, \x85, \xe3 (de nuevo), \x80 (de nuevo), \x86 \xe3 (de nuevo), \x83, \xb5, \xe3 (de nuevo), \x83 (de nuevo), \xb6.

Desordenado no es? ¿Ves el problema?

Esto no coincidirá con caracteres "latinos" (que asumo que se refiere a cosas como a-z) porque en UTF-8 todos usan un solo byte por debajo de 0x80, y ninguno de ellos está en esa clase de caracteres desordenados.

No coincidirá "中" ya sea porque "中" tiene tres "caracteres", y su expresión regular solo coincide con un "carácter" de esa larga lista extraña. Prueba assert(std::regex_match("中", std::regex("..."))) y verás.

Si agregas un + funciona porque "中" tiene tres de esos "caracteres" en tu lista larga y rara, y ahora tu expresión regular coincide con uno o más.

Si en su lugar agrega {1} no coincide porque volvemos a emparejar tres "caracteres" contra uno.

Incidentalmente "中" coincide "中" porque estamos coincidiendo los tres "caracteres" contra los mismos tres "caracteres" en el mismo orden.

Que la expresión regular con + realmente coincidirá con algunas cosas no deseadas porque no le importa el orden. Cualquier carácter que se pueda hacer de esa lista de bytes en UTF-8 coincidirá. Coincidirá con "\xe3\x81\x81" (U U+3041) e incluso coincidirá con una entrada UTF-8 no válida como "\xe3\xe3\xe3\xe3".

El mayor problema es que está utilizando una biblioteca de expresiones regulares que ni siquiera tiene soporte de nivel 1 para Unicode, el mínimo requerir. Munges bytes y no hay mucho que su preciosa regex pequeña puede hacer al respecto.

Y el problema aún mayor es que está utilizando un conjunto de caracteres codificados para especificar "cualquier Kanji japonés o carácter chino". ¿Por qué no usar la propiedad Unicode Script para eso?

R"(\p{Script=Han})"

Oh bien, esto no funcionará con expresiones regulares de C++11. Por un momento casi me olvido de que son molestamente peores que inútiles con Unicode.

Entonces, ¿qué debería hacer?

Puede decodificar su entrada en un std::u32string y usar char32_t por todas partes para la coincidencia. Eso no le daría este lío, pero seguiría siendo rangos de codificación dura y excepciones cuando se refiere a "un conjunto de caracteres que comparten una cierta propiedad".

Le recomiendo que se olvide de las expresiones regulares de C++11 y use alguna biblioteca de expresiones regulares que tenga el mínimo nivel 1 de soporte Unicode, como la de ICU.

 33
Author: R. Martinho Fernandes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-16 07:40:53