2010-12-02 11 views
20

¿Cuál es una buena forma de saber si una cadena contiene texto en un idioma de derecha a izquierda?¿Cómo detectar si un personaje pertenece a un idioma de derecha a izquierda?

He encontrado que esto question que sugiere el siguiente enfoque:

public bool IsArabic(string strCompare) 
{ 
    char[] chars = strCompare.ToCharArray(); 
    foreach (char ch in chars) 
    if (ch >= '\u0627' && ch <= '\u0649') return true; 
    return false; 
} 

bien esto puede funcionar para árabe, esto no parece para cubrir otros idiomas RTL como el hebreo. ¿Existe una forma genérica de saber que un personaje en particular pertenece a un lenguaje RTL?

Respuesta

20

Los caracteres Unicode tienen propiedades diferentes asociadas. Estas propiedades no pueden derivarse del punto de código; necesitas una tabla que te diga si un personaje tiene cierta propiedad o no.

Le interesan los caracteres con propiedad bidireccional "R" o "AL" (RandALCat).

Un personaje de RandALCat es un personaje con direccionalidad de derecha a izquierda sin ambigüedades.

Aquí está la lista completa de Unicode 3.2 (de RFC 3454):

 
D. Bidirectional tables 

D.1 Characters with bidirectional property "R" or "AL" 

----- Start Table D.1 ----- 
05BE 
05C0 
05C3 
05D0-05EA 
05F0-05F4 
061B 
061F 
0621-063A 
0640-064A 
066D-066F 
0671-06D5 
06DD 
06E5-06E6 
06FA-06FE 
0700-070D 
0710 
0712-072C 
0780-07A5 
07B1 
200F 
FB1D 
FB1F-FB28 
FB2A-FB36 
FB38-FB3C 
FB3E 
FB40-FB41 
FB43-FB44 
FB46-FBB1 
FBD3-FD3D 
FD50-FD8F 
FD92-FDC7 
FDF0-FDFC 
FE70-FE74 
FE76-FEFC 
----- End Table D.1 ----- 

Aquí hay un código para obtener la lista completa de Unicode 6.0:

var url = "http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt"; 

var query = from record in new WebClient().DownloadString(url).Split('\n') 
      where !string.IsNullOrEmpty(record) 
      let properties = record.Split(';') 
      where properties[4] == "R" || properties[4] == "AL" 
      select int.Parse(properties[0], NumberStyles.AllowHexSpecifier); 

foreach (var codepoint in query) 
{ 
    Console.WriteLine(codepoint.ToString("X4")); 
} 

Tenga en cuenta que estos valores son puntos de código Unicode. Las cadenas en C# /. NET están codificadas en UTF-16 y deben convertirse a puntos de código Unicode primero (consulte Char.ConvertToUtf32). Aquí es un método que comprueba si una cadena contiene al menos un carácter RandALCat:

static void IsAnyCharacterRightToLeft(string s) 
{ 
    for (var i = 0; i < s.Length; i += char.IsSurrogatePair(s, i) ? 2 : 1) 
    { 
     var codepoint = char.ConvertToUtf32(s, i); 
     if (IsRandALCat(codepoint)) 
     { 
      return true; 
     } 
    } 
    return false; 
} 
+0

¡Gracias por esto! Me preguntaba qué pensarías del enfoque de Brent. –

+1

@Patrick Kluge: el motor de expresiones regulares aparentemente contiene una tabla de propiedades Unicode. Pero no veo bloques con nombre para todos los personajes de RandALCat. Por lo tanto, depende del nivel de corrección que necesite: si detectar árabe, hebreo y algunos otros caracteres es lo suficientemente bueno para usted, busque expresiones regulares. Si necesita detectar cualquier personaje RandALCat en existencia, construya su propia tabla y verifique la cadena de entrada usted mismo como se muestra arriba. – dtb

+0

Me pregunto qué piensa del símbolo ۞, que es tratado de derecha a izquierda por productos de software como Google Chrome y MS Word, pero no está marcado como RandALCat en la especificación Unicode. –

16

Usted puede intentar usar "named blocks" en regular expressions. Solo selecciona los bloques que están de derecha a izquierda y forma la expresión regular. Por ejemplo:

\p{IsArabic}|\p{IsHebrew} 

Si esa expresión regular devuelve verdadero, entonces hubo al menos un carácter hebreo o árabe en la cadena.

6

Todos "AL" o "R" de Unicode 6.0 (de http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt)

bool hasRandALCat = 0; 
if(c >= 0x5BE && c <= 0x10B7F) 
{ 
    if(c <= 0x85E) 
    { 
     if(c == 0x5BE)      hasRandALCat = 1; 
     else if(c == 0x5C0)     hasRandALCat = 1; 
     else if(c == 0x5C3)     hasRandALCat = 1; 
     else if(c == 0x5C6)     hasRandALCat = 1; 
     else if(0x5D0 <= c && c <= 0x5EA)  hasRandALCat = 1; 
     else if(0x5F0 <= c && c <= 0x5F4)  hasRandALCat = 1; 
     else if(c == 0x608)     hasRandALCat = 1; 
     else if(c == 0x60B)     hasRandALCat = 1; 
     else if(c == 0x60D)     hasRandALCat = 1; 
     else if(c == 0x61B)     hasRandALCat = 1; 
     else if(0x61E <= c && c <= 0x64A)  hasRandALCat = 1; 
     else if(0x66D <= c && c <= 0x66F)  hasRandALCat = 1; 
     else if(0x671 <= c && c <= 0x6D5)  hasRandALCat = 1; 
     else if(0x6E5 <= c && c <= 0x6E6)  hasRandALCat = 1; 
     else if(0x6EE <= c && c <= 0x6EF)  hasRandALCat = 1; 
     else if(0x6FA <= c && c <= 0x70D)  hasRandALCat = 1; 
     else if(c == 0x710)     hasRandALCat = 1; 
     else if(0x712 <= c && c <= 0x72F)  hasRandALCat = 1; 
     else if(0x74D <= c && c <= 0x7A5)  hasRandALCat = 1; 
     else if(c == 0x7B1)     hasRandALCat = 1; 
     else if(0x7C0 <= c && c <= 0x7EA)  hasRandALCat = 1; 
     else if(0x7F4 <= c && c <= 0x7F5)  hasRandALCat = 1; 
     else if(c == 0x7FA)     hasRandALCat = 1; 
     else if(0x800 <= c && c <= 0x815)  hasRandALCat = 1; 
     else if(c == 0x81A)     hasRandALCat = 1; 
     else if(c == 0x824)     hasRandALCat = 1; 
     else if(c == 0x828)     hasRandALCat = 1; 
     else if(0x830 <= c && c <= 0x83E)  hasRandALCat = 1; 
     else if(0x840 <= c && c <= 0x858)  hasRandALCat = 1; 
     else if(c == 0x85E)     hasRandALCat = 1; 
    } 
    else if(c == 0x200F)      hasRandALCat = 1; 
    else if(c >= 0xFB1D) 
    { 
     if(c == 0xFB1D)      hasRandALCat = 1; 
     else if(0xFB1F <= c && c <= 0xFB28) hasRandALCat = 1; 
     else if(0xFB2A <= c && c <= 0xFB36) hasRandALCat = 1; 
     else if(0xFB38 <= c && c <= 0xFB3C) hasRandALCat = 1; 
     else if(c == 0xFB3E)     hasRandALCat = 1; 
     else if(0xFB40 <= c && c <= 0xFB41) hasRandALCat = 1; 
     else if(0xFB43 <= c && c <= 0xFB44) hasRandALCat = 1; 
     else if(0xFB46 <= c && c <= 0xFBC1) hasRandALCat = 1; 
     else if(0xFBD3 <= c && c <= 0xFD3D) hasRandALCat = 1; 
     else if(0xFD50 <= c && c <= 0xFD8F) hasRandALCat = 1; 
     else if(0xFD92 <= c && c <= 0xFDC7) hasRandALCat = 1; 
     else if(0xFDF0 <= c && c <= 0xFDFC) hasRandALCat = 1; 
     else if(0xFE70 <= c && c <= 0xFE74) hasRandALCat = 1; 
     else if(0xFE76 <= c && c <= 0xFEFC) hasRandALCat = 1; 
     else if(0x10800 <= c && c <= 0x10805) hasRandALCat = 1; 
     else if(c == 0x10808)     hasRandALCat = 1; 
     else if(0x1080A <= c && c <= 0x10835) hasRandALCat = 1; 
     else if(0x10837 <= c && c <= 0x10838) hasRandALCat = 1; 
     else if(c == 0x1083C)     hasRandALCat = 1; 
     else if(0x1083F <= c && c <= 0x10855) hasRandALCat = 1; 
     else if(0x10857 <= c && c <= 0x1085F) hasRandALCat = 1; 
     else if(0x10900 <= c && c <= 0x1091B) hasRandALCat = 1; 
     else if(0x10920 <= c && c <= 0x10939) hasRandALCat = 1; 
     else if(c == 0x1093F)     hasRandALCat = 1; 
     else if(c == 0x10A00)     hasRandALCat = 1; 
     else if(0x10A10 <= c && c <= 0x10A13) hasRandALCat = 1; 
     else if(0x10A15 <= c && c <= 0x10A17) hasRandALCat = 1; 
     else if(0x10A19 <= c && c <= 0x10A33) hasRandALCat = 1; 
     else if(0x10A40 <= c && c <= 0x10A47) hasRandALCat = 1; 
     else if(0x10A50 <= c && c <= 0x10A58) hasRandALCat = 1; 
     else if(0x10A60 <= c && c <= 0x10A7F) hasRandALCat = 1; 
     else if(0x10B00 <= c && c <= 0x10B35) hasRandALCat = 1; 
     else if(0x10B40 <= c && c <= 0x10B55) hasRandALCat = 1; 
     else if(0x10B58 <= c && c <= 0x10B72) hasRandALCat = 1; 
     else if(0x10B78 <= c && c <= 0x10B7F) hasRandALCat = 1; 
    } 
} 
1

EDIT:

Esto es lo que uso ahora, que incluye los caracteres Vowelization y todo en hebreo y árabe:

[\u0591-\u07FF] 

vieja respuesta:

Si necesita detectar el lenguaje RTL en una frase, esta simplificada RegEx probablemente será suficiente:

[א-ת؀-ۿ] 

Si uno quiere escribir algo en hebreo se tendrá que utilizar uno de estos personajes, y el el caso es similar con el árabe.

No incluye caracteres de vocalización, por lo que si necesita capturar todas las palabras completas o absolutamente todos los caracteres RTL, es mejor utilizar una de las otras respuestas. Los caracteres de vocalización en hebreo son muy raros en textos no poéticos. No sé sobre textos en árabe.

Cuestiones relacionadas