2011-08-12 13 views
10

Necesito una expresión regular para language tag como se define en BCP 47.Expresión regular para una etiqueta de idioma (como se define en BCP47)

Sé que la sintaxis completa de BNF está disponible en http://www.rfc-editor.org/rfc/bcp/bcp47.txt y que podría usarla para escribir la mía, pero ojalá haya una ya disponible.

+0

Haha. Hice esto por mí hace un par de semanas, pero desafortunadamente mi disco (que era un SSD nuevo) murió. Voy a echar un vistazo de nuevo :) – porges

+0

@PaulPRO: las etiquetas de idioma son definitivamente regulares. – porges

Respuesta

14

se ve así:

^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux| 
i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban| 
cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language> 
([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8}) 
(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8} 
|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))* 
(-(?<privateUse>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUse>x(-[A-Za-z0-9]{1,8})+))$ 

Este es el código para generar ella (en C#):

(errores tipográficos yo pueda haber cometido)
var regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)"; 
var irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)"; 
var grandfathered = "(?<grandfathered>" + irregular + "|" + regular + ")"; 
var privateUse = "(?<privateUse>x(-[A-Za-z0-9]{1,8})+)"; 
var singleton = "[0-9A-WY-Za-wy-z]"; 
var extension = "(?<extension>" + singleton + "(-[A-Za-z0-9]{2,8})+)"; 
var variant = "(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})"; 
var region = "(?<region>[A-Za-z]{2}|[0-9]{3})"; 
var script = "(?<script>[A-Za-z]{4})"; 
var extlang = "(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2})"; 
var language = "(?<language>([A-Za-z]{2,3}(-" + extlang + ")?)|[A-Za-z]{4}|[A-Za-z]{5,8})"; 
var langtag = "(" + language + "(-" + script + ")?" + "(-" + region + ")?" + "(-" + variant + ")*" + "(-" + extension + ")*" + "(-" + privateUse + ")?" + ")"; 
var languageTag = @"^(" + grandfathered + "|" + langtag + "|" + privateUse + ")$"; 

Console.WriteLine(languageTag); 

no puedo garantizar su exactitud, pero funciona bien en los ejemplos en el Apéndice A.

Dependiendo de su entorno, es posible que deba eliminar los grupos de captura nombrados "?<...>".

+0

¡Increíble, gracias! Funciona muy bien con PHP después de hacer algunos cambios. Me preguntaba, ¿qué hacen esos "grupos de captura nombrados"? Esta no es una característica disponible en la sintaxis de expresiones regulares de PHP hasta donde yo sé, pero estoy interesado. –

+1

@Tim Solo le permite acceder a grupos por nombre en lugar de índice. p.ej. 'match.Groups [" variant "]' – porges

+1

No creo que esto resuelva las secciones de "derechos adquiridos regularmente" correctamente (se analizarán como una etiqueta normal en lugar de como el código especial que son). Tendrá que colocar la variable 'grandfathered' antes de la variable' langtag' durante la definición de 'languageTag' –

2

Una versión optimizada que funciona en PHP.

/^(?<grandfathered>(?:en-GB-oed|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|t(?:a[oy]|su))|sgn-(?:BE-(?:FR|NL)|CH-DE))|(?:art-lojban|cel-gaulish|no-(?:bok|nyn)|zh-(?:guoyu|hakka|min(?:-nan)?|xiang)))|(?:(?<language>(?:[A-Za-z]{2,3}(?:-(?<extlang>[A-Za-z]{3}(?:-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(?:-(?<script>[A-Za-z]{4}))?(?:-(?<region>[A-Za-z]{2}|[0-9]{3}))?(?:-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(?:-(?<extension>[0-9A-WY-Za-wy-z](?:-[A-Za-z0-9]{2,8})+))*)(?:-(?<privateUse>x(?:-[A-Za-z0-9]{1,8})+))?$/Di 
Cuestiones relacionadas