tester regex perl unicode locale pcre

regex - tester - ¿Debemos considerar el uso de range[az] como un error?



perl regex tester (3)

Posibles errores locales

El problema al que se enfrenta no es con las clases de caracteres POSIX per se , sino con el hecho de que las clases dependen de la configuración regional. Por ejemplo, regex (7) dice:

Dentro de una expresión de corchete, el nombre de una clase de caracteres incluida entre "[:" y ":]" representa la lista de todos los caracteres que pertenecen a esa clase ... Estas representan las clases de caracteres definidas en wctype (3). Un local puede proporcionar otros.

El énfasis es mío, pero la página del manual dice claramente que las clases de caracteres dependen de la configuración regional. Además, wctype (3) dice:

El comportamiento de wctype () depende de la categoría LC_CTYPE de la configuración regional actual.

En otras palabras, si su configuración regional define incorrectamente una clase de caracteres, entonces es un error que se debe presentar en relación con la configuración regional específica. Por otro lado, si la clase de caracteres simplemente define el conjunto de caracteres de una manera que no está esperando, entonces puede que no sea un error; Puede que solo sea un problema que necesita ser codificado.

Clases de personajes como atajos

Las clases de caracteres son atajos para definir conjuntos. Ciertamente, no está restringido a los conjuntos predefinidos para su configuración regional, y es libre de usar los conjuntos de caracteres Unicode definidos por perlre (1), o simplemente cree los conjuntos de manera explícita si eso proporciona mayor precisión.

Ya lo sabes, así que no estoy tratando de ser pedante. Solo estoy señalando que si no puede o no quiere arreglar la configuración regional (que es la fuente del problema aquí), entonces debería usar un conjunto explícito, como lo ha hecho.

Una clase de conveniencia solo es conveniente si funciona para su caso de uso. Si no es así, ¡tíralo por la borda!

En mi locale (et_EE) [az] significa:

abcdefghijklmnopqrsšz

Entonces, no se incluyen 6 caracteres ASCII ( tuvwxy ) y uno del alfabeto estonio ( ž ). Veo muchos módulos que todavía están usando expresiones regulares como

//A[0-9A-Z_a-z]+/z/

Para mí, parece una forma incorrecta de definir el rango de caracteres alfanuméricos ASCII y creo que debería reemplazarse con:

//A/p{PosixAlnum}+/z/

¿Es el primero todavía considerado de manera idiomática? ¿O solución aceptada? O un error?

¿O tiene alguna otra advertencia?


Como esta pregunta va más allá de Perl, me interesó averiguar cómo funciona en general. Probando esto en lenguajes de programación populares con soporte nativo de expresiones regulares, Perl, PHP, Python, Ruby, Java y Javascript, las conclusiones son:

  • [az] coincidirá ASCII-7 rango ASCII-7 az en todos y cada uno de esos idiomas, siempre, y la configuración regional no lo afectará de ninguna manera. Los caracteres como ž y š nunca se combinan.
  • /w puede o no coincidir con los caracteres ž y š , según el lenguaje de programación y los parámetros dados al crear una expresión regular. Para esta expresión, la variedad es mayor, ya que en algunos idiomas nunca están emparejados, sin importar las opciones, en otros siempre están emparejados y en algunos depende.
  • POSIX [[:alpha:]] y Unicode /p{Alpha} y /p{L} , si están soportados por el sistema de expresiones regulares del lenguaje de programación en cuestión y se usa la configuración apropiada, coincidirán con caracteres como ž y š .

Tenga en cuenta que la "Configuración apropiada" no requirió cambio de configuración regional: el cambio de configuración regional no tuvo impacto en los resultados en ninguno de los sistemas probados.

Para estar en el lado seguro, también probé la línea de comandos Perl, grep y awk. Desde allí, la línea de comando Perl se comporta de manera idéntica a la anterior. Sin embargo, grep y awk parecen tener un comportamiento diferente de los demás en cuanto a eso, la configuración regional también es importante para [az] . El comportamiento también es específico para la versión y la implementación.

En ese contexto, grep, awk o herramientas de línea de comandos similares, estoy de acuerdo en que usar un rango de rango sin la definición de la configuración regional podría considerarse un error, ya que realmente no puede saber con qué termina.

Si vamos a más detalles por idioma, el estado parece ser:

Java

En java, /p{Alpha} funciona como [az] si no se especifica la clase Unicode, y el carácter alfabético de Unicode si es, coincidiendo con ž . /w coincidirá con caracteres como ž si el indicador Unicode está presente y no si no lo está, y /p{L} coincidirá independientemente del indicador Unicode. No hay expresiones regulares compatibles con la configuración regional o soporte para [[alpha]] .

PHP

En PHP /w , [[:alpha:]] y /p{L} coincidirán con caracteres como ž si el interruptor Unicode está presente, y no si no lo está. /p{Alpha} no es compatible. La configuración regional no tiene ningún impacto en las expresiones regulares.

Pitón

/w coincidirá con los caracteres mencionados si el indicador Unicode está presente y el indicador de configuración regional no está presente. Para cadenas de Unicode, el indicador de Unicode se asume de forma predeterminada si se usa Python 3, pero no con Python 2. Unicode /p{Alpha} , /p{L} o POSIX [[:alpha:]] no se admiten en Python.

El modificador para usar expresiones regulares específicas del entorno local aparentemente solo funciona para conjuntos de caracteres con 1 byte por carácter , lo que lo hace inutilizable para Unicode.

Perl

/w coincide con los caracteres mencionados anteriormente además de [az] . Unicode /p{Letter} , /p{Alpha} y POSIX [[:alpha:]] son compatibles y funcionan como se espera. Las banderas Unicode y locale para expresiones regulares no cambiaron los resultados, y tampoco cambiaron de locale o use locale; / no locale; .

Behavour no cambia si ejecutamos pruebas utilizando la línea de comandos Perl.

Rubí

[az] y /w detectan solo los caracteres [az] , independientemente de las opciones. Se admiten Unicode /p{Letter} , /p{Alpha} y POSIX [[:alpha:]] y funcionan como se espera. El local no tiene impacto.

Javascript

[az] y /w siempre detectan solo los caracteres [az] . Hay soporte para el conmutador /u Unicode en ECMA2015, que es principalmente compatible con los principales navegadores, pero no ofrece soporte para [[:alpha:]] , /p{Alpha} o /p{L} ni cambia el comportamiento de /w . El conmutador Unicode agrega el tratamiento de los caracteres Unicode como un solo carácter , lo que ha sido un problema anteriormente.

La situación es la misma para javascript del lado del cliente así como para Node.js.

AWK

Para AWK, hay una descripción más larga del estado publicado en el artículo A.8 Regexp Ranges and Locales: A Long Sad Story . Detalla que en el viejo mundo de las herramientas de Unix, [az] era la forma correcta de detectar letras minúsculas y así es como funcionaban las herramientas de la época. Sin embargo, POSIX de 1992 introdujo las configuraciones regionales y cambió la interpretación de las clases de caracteres para que el orden de los caracteres se definiera por orden de intercalación, vinculándolo a la localización Esto también fue adoptado por AWK de la época (serie 3.x), que dio lugar a varios problemas. Cuando se desarrolló la serie 4.x, POSIX 2008 definió el orden como no definido, y el mantenedor volvió a su comportamiento original.

Hoy en día se utiliza principalmente la versión 4.x de AWK. Cuando se usa eso, [az] coincide con az ignorando cualquier cambio de configuración regional, y /w y [[:alpha:]] coincidirán con caracteres específicos de la configuración regional. Unicode / p {Alpha} y / p {L} no son compatibles.

grep

Grep (así como sed, ed) usa GNU Basic Regular Expressions, que es un sabor antiguo. No tiene soporte para clases de caracteres Unicode.

Al menos gnu grep 2.16 y 2.25 parece seguir el posix de 1992 en que la configuración regional también es importante para [az] , así como para /w y [[:alpha:]] . Esto significa, por ejemplo, que [az] solo coincide con z en el conjunto xuzvöä si se usa la configuración regional estonia.

Código de prueba utilizado enumerado a continuación para cada idioma.

Java (1.8.0_131)

import java.util.regex.*; import java.util.Locale; public class RegExpTest { public static void main(String args[]) { verify("v", 118); verify("š", 353); verify("ž", 382); tryWith("v"); tryWith("š"); tryWith("ž"); } static void tryWith(String input) { matchWith("[a-z]", input); matchWith("//w", input); matchWith("//p{Alpha}", input); matchWith("//p{L}", input); matchWith("[[:alpha:]]", input); } static void matchWith(String pattern, String input) { printResult(Pattern.compile(pattern), input); printResult(Pattern.compile(pattern, Pattern.UNICODE_CHARACTER_CLASS), input); } static void printResult(Pattern pattern, String input) { System.out.printf("%s/t%03d/t%5s/t%-10s/t%-10s/t%-5s%n", input, input.codePointAt(0), Locale.getDefault(), specialFlag(pattern.flags()), pattern, pattern.matcher(input).matches()); } static String specialFlag(int flags) { if ((flags & Pattern.UNICODE_CHARACTER_CLASS) == Pattern.UNICODE_CHARACTER_CLASS) { return "UNICODE_FLAG"; } return ""; } static void verify(String str, int code) { if (str.codePointAt(0) != code) { throw new RuntimeException("your editor is not properly configured for this character: " + str); } } }

PHP (7.1.5)

<?php /* PHP, even with 7, only has binary strings that can be operated with unicode-aware functions, if needed. So functions operating them need to be told which charset to use. When there is encoding assumed and not specified, PHP defaults to ISO-8859-1. */ // PHP7 and extension=php_intl.dll enabled in PHP.ini is needed for IntlChar class function codepoint($char) { return IntlChar::ord($char); } function verify($inputp, $code) { if (codepoint($inputp) != $code) { throw new Exception(sprintf(''Your editor is not configured correctly for %s (result %s, should be %s)'', $inputp, codepoint($inputp), $code)); } } $rowindex = 0; $origlocale = getlocale(); verify(''v'', 118); verify(''š'', 353); // https://en.wikipedia.org/wiki/%C5%A0#Computing_code verify(''ž'', 382); // https://en.wikipedia.org/wiki/%C5%BD#Computing_code function tryWith($input) { matchWith(''[a-z]'', $input); matchWith(''//w'', $input); matchWith(''[[:alpha:]]'', $input); // POSIX, http://www.regular-expressions.info/posixbrackets.html matchWith(''/p{L}'', $input); } function matchWith($pattern, $input) { global $origlocale; selectLocale($origlocale); printResult("/^$pattern/$/", $input); printResult("/^$pattern/$/u", $input); selectLocale(''C''); # default (root) locale printResult("/^$pattern/$/", $input); printResult("/^$pattern/$/u", $input); selectLocale([''et_EE'', ''et_EE.UTF-8'', ''Estonian_Estonia.1257'']); printResult("/^$pattern/$/", $input); printResult("/^$pattern/$/u", $input); selectLocale($origlocale); } function selectLocale($locale) { if (!is_array($locale)) { $locale = [$locale]; } // On Windows, no UTF-8 locale can be set // https://.com/a/16120506/365237 // https://msdn.microsoft.com/en-us/library/x99tb11d.aspx // Available Windows locales // https://docs.moodle.org/dev/Table_of_locales $retval = setlocale(LC_ALL, $locale); //printf("setting locale %s, retval was %s/n", join('','', $locale), $retval); if ($retval === false || $retval === null) { throw new Exception(sprintf(''Setting locale %s failed'', join('','', $locale))); } } function getlocale() { return setlocale(LC_ALL, 0); } function printResult($pattern, $input) { global $rowindex; printf("%2d: %s/t%03d/t%-20s/t%-25s/t%-10s/t%-5s/n", $rowindex, $input, codepoint($input), getlocale(), specialFlag($pattern), $pattern, (preg_match($pattern, $input) === 1)?''true'':''false''); $rowindex = $rowindex + 1; } function specialFlag($pattern) { $arr = explode(''/'',$pattern); $lastelem = array_pop($arr); if (strpos($lastelem, ''u'') !== false) { return ''UNICODE''; } return ''''; } tryWith(''v''); tryWith(''š''); tryWith(''ž'');

Python (3.5.3)

# -*- coding: utf-8 -*- # with python, there are two strings: unicode strings and regular ones. # when you use unicode strings, regular expressions also take advantage of it, # so no need to tell that separately. However, if you want to be using specific # locale, that you need to tell. # Note that python3 regexps defaults to unicode mode if unicode regexp string is used, # python2 does not. Also strings are unicode strings in python3 by default. # summary: [a-z] is always [a-z], /w will match if unicode flag is present and # locale flag is not present, no unicode /p{Letter} or POSIX :alpha: exists. # Letters outside ascii-7 never match /w if locale-specific # regexp is used, as it only supports charsets with one byte per character # (https://lists.gt.net/python/python/850772). # Note that in addition to standard https://docs.python.org/3/library/re.html, more # complete https://pypi.python.org/pypi/regex/ third-party regexp library exists. import re, locale def verify(inputp, code): if (ord(inputp[0]) != code): raise Exception(''Your editor is not configured correctly for %s (result %s)'' % (inputp, ord(inputp[0]))) return rowindex = 0 origlocale = locale.getlocale(locale.LC_ALL) verify(u''v'', 118) verify(u''š'', 353) verify(u''ž'', 382) def tryWith(input): matchWith(u''[a-z]'', input) matchWith(u''//w'', input) def matchWith(pattern, input): global origlocale locale.setlocale(locale.LC_ALL, origlocale) printResult(re.compile(pattern), input) printResult(re.compile(pattern, re.UNICODE), input) printResult(re.compile(pattern, re.UNICODE | re.LOCALE), input) matchWith2(pattern, input, ''C'') # default (root) locale matchWith2(pattern, input, ''et_EE'') matchWith2(pattern, input, ''et_EE.UTF-8'') matchWith2(pattern, input, ''Estonian_Estonia.1257'') # Windows locale locale.setlocale(locale.LC_ALL, origlocale) def matchWith2(pattern, input, localeParam): try: locale.setlocale(locale.LC_ALL, localeParam) # default (root) locale printResult(re.compile(pattern), input) printResult(re.compile(pattern, re.UNICODE), input) printResult(re.compile(pattern, re.UNICODE | re.LOCALE), input) except locale.Error: print("Locale %s not supported on this platform" % localeParam) def printResult(pattern, input): global rowindex try: print("%2d: %s/t%03d/t%-20s/t%-25s/t%-10s/t%-5s" % / (rowindex, input, ord(input[0]), locale.getlocale(), / specialFlag(pattern.flags), / pattern.pattern, pattern.match(input) != None)) except UnicodeEncodeError: print("%2d: %s/t%03d/t%-20s/t%-25s/t%-10s/t%-5s" % / (rowindex, ''?'', ord(input[0]), locale.getlocale(), / specialFlag(pattern.flags), / pattern.pattern, pattern.match(input) != None)) rowindex = rowindex + 1 def specialFlag(flags): ret = [] if ((flags & re.UNICODE) == re.UNICODE): ret.append("UNICODE_FLAG") if ((flags & re.LOCALE) == re.LOCALE): ret.append("LOCALE_FLAG") return '',''.join(ret) tryWith(u''v'') tryWith(u''š'') tryWith(u''ž'')

Perl (v5.22.3)

# Summary: [a-z] is always [a-z], /w always seems to recognize given test chars and # unicode /p{Letter}, /p{Alpha} and POSIX :alpha: are supported. # Unicode and locale flags for regular expression didn''t matter in this use case. use warnings; use strict; use utf8; use v5.14; use POSIX qw(locale_h); use Encode; binmode STDOUT, "utf8"; sub codepoint { my $inputp = $_[0]; return unpack(''U*'', $inputp); } sub verify { my($inputp, $code) = @_; if (codepoint($inputp) != $code) { die sprintf(''Your editor is not configured correctly for %s (result %s)'', $inputp, codepoint($inputp)) } } sub getlocale { return setlocale(LC_ALL); } my $rowindex = 0; my $origlocale = getlocale(); verify(''v'', 118); verify(''š'', 353); verify(''ž'', 382); # printf(''orig locale is %s'', $origlocale); sub tryWith { my ($input) = @_; matchWith(''[a-z]'', $input); matchWith(''/w'', $input); matchWith(''[[:alpha:]]'', $input); matchWith(''/p{Alpha}'', $input); matchWith(''/p{L}'', $input); } sub matchWith { my ($pattern, $input) = @_; my @locales_to_test = ($origlocale, ''C'',''C.UTF-8'', ''et_EE.UTF-8'', ''Estonian_Estonia.UTF-8''); for my $testlocale (@locales_to_test) { use locale; # printf("Testlocale %s/n", $testlocale); setlocale(LC_ALL, $testlocale); printResult($pattern, $input, ''''); printResult($pattern, $input, ''u''); printResult($pattern, $input, ''l''); printResult($pattern, $input, ''a''); }; no locale; setlocale(LC_ALL, $origlocale); printResult($pattern, $input, ''''); printResult($pattern, $input, ''u''); printResult($pattern, $input, ''l''); printResult($pattern, $input, ''a''); } sub printResult{ no warnings ''locale''; # for this test, as we want to be able to test non-unicode-compliant locales as well # remove this for real usage my ($pattern, $input, $flags) = @_; my $regexp = qr/$pattern/; $regexp = qr/$pattern/u if ($flags eq ''u''); $regexp = qr/$pattern/l if ($flags eq ''l''); printf("%2d: %s/t%03d/t%-20s/t%-25s/t%-10s/t%-5s/n", $rowindex, $input, codepoint($input), getlocale(), $flags, $pattern, (($input =~ $regexp) ? ''true'':''false'')); $rowindex = $rowindex + 1; } tryWith(''v''); tryWith(''š''); tryWith(''ž'');

Ruby (ruby 2.2.6p396 (2016-11-15 revisión 56800) [x64-mingw32])

# -*- coding: utf-8 -*- # Summary: [a-z] and /w are always [a-z], unicode /p{Letter}, /p{Alpha} and POSIX # :alpha: are supported. Locale does not have impact. # Ruby doesn''t seem to be able to interact very well with locale without ''locale'' # rubygem (https://github.com/mutoh/locale), so that is used. require ''rubygems'' require ''locale'' def verify(inputp, code) if (inputp.unpack(''U*'')[0] != code) raise Exception, sprintf(''Your editor is not configured correctly for %s (result %s)'', inputp, inputp.unpack(''U*'')[0]) end end $rowindex = 0 $origlocale = Locale.current $origcharmap = Encoding.locale_charmap verify(''v'', 118) verify(''š'', 353) verify(''ž'', 382) # printf(''orig locale is %s.%s'', $origlocale, $origcharmap) def tryWith(input) matchWith(''[a-z]'', input) matchWith(''/w'', input) matchWith(''[[:alpha:]]'', input) matchWith(''/p{Alpha}'', input) matchWith(''/p{L}'', input) end def matchWith(pattern, input) locales_to_test = [$origlocale, ''C'', ''et_EE'', ''Estonian_Estonia''] for testlocale in locales_to_test Locale.current = testlocale printResult(Regexp.new(pattern), input) printResult(Regexp.new(pattern.force_encoding(''utf-8''),Regexp::FIXEDENCODING), input) end Locale.current = $origlocale end def printResult(pattern, input) printf("%2d: %s/t%03d/t%-20s/t%-25s/t%-10s/t%-5s/n", $rowindex, input, input.unpack(''U*'')[0], Locale.current, specialFlag(pattern), pattern, !pattern.match(input).nil?) $rowindex = $rowindex + 1 end def specialFlag(pattern) return pattern.encoding end tryWith(''v'') tryWith(''š'') tryWith(''ž'')

Javascript (node.js) (v6.10.3)

function match(pattern, input) { try { var re = new RegExp(pattern, "u"); return input.match(re) !== null; } catch(e) { return ''unsupported''; } } function regexptest() { var chars = [ String.fromCodePoint(118), String.fromCodePoint(353), String.fromCodePoint(382) ]; for (var i = 0; i < chars.length; i++) { var char = chars[i]; console.log( char +''/t'' + char.codePointAt(0) +''/t'' +(match("[a-z]", char)) +''/t'' +(match("//w", char)) +''/t'' +(match("[[:alpha:]]", char)) +''/t'' +(match("//p{Alpha}", char)) +''/t'' +(match("//p{L}", char)) ); } } regexptest();

Javascript (navegadores web)

function match(pattern, input) { try { var re = new RegExp(pattern, "u"); return input.match(re) !== null; } catch(e) { return ''unsupported''; } } window.onload = function() { var chars = [ String.fromCodePoint(118), String.fromCodePoint(353), String.fromCodePoint(382) ]; for (var i = 0; i < chars.length; i++) { var char = chars[i]; var table = document.getElementById(''results''); table.innerHTML += ''<tr><td>'' + char +''</td><td>'' + char.codePointAt(0) +''</td><td>'' +(match("[a-z]", char)) +''</td><td>'' +(match("//w", char)) +''</td><td>'' +(match("[[:alpha:]]", char)) +''</td><td>'' +(match("//p{Alpha}", char)) +''</td><td>'' +(match("//p{L}", char)) +''</td></tr>''; } }

table { border-collapse: collapse; } table td, table th { border: 1px solid black; } table tr:first-child th { border-top: 0; } table tr:last-child td { border-bottom: 0; } table tr td:first-child, table tr th:first-child { border-left: 0; } table tr td:last-child, table tr th:last-child { border-right: 0; }

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <table id="results"> <tr> <td>char</td> <td>codepoint</td> <td>[a-z]</td> <td>/w</td> <td>[[:alpha:]]</td> <td>/p{Alpha}</td> <td>/p{L}</td> </tr> </table> </body> </html>

AWK (GNU Awk 4.1.3)

$ echo "xyzvöä" | LC_ALL=C awk ''{match($0,"[a-z]+",a)}END{print a[0]}'' xyzv $ echo "xyzvöä" | LC_ALL=et_EE.utf8 awk ''{match($0,"[a-z]+",a)}END{print a[0]}'' xyzv $ echo "xyzvöä" | LC_ALL=C awk ''{match($0,"//w+",a)}END{print a[0]}'' xyzv $ echo "xyzvöä" | LC_ALL=et_EE.utf8 awk ''{match($0,"//w+",a)}END{print a[0]}'' xyzvöä $ echo "xyzvöä" | LC_ALL=C awk ''{match($0,"[[:alpha:]]+",a)}END{print a[0]}'' xyzv $ echo "xyzvöä" | LC_ALL=et_EE.utf8 awk ''{match($0,"[[:alpha:]]+",a)}END{print a[0]}'' xyzvöä

AWK (GNU Awk 3.1.8)

$ echo "xyzvöä" | LC_ALL=C awk ''{match($0,"[a-z]+",a)}END{print a[0]}'' xyzv $ echo "xyzvöä" | LC_ALL=et_EE.utf8 awk ''{match($0,"[a-z]+",a)}END{print a[0]}'' z $ echo "xyzvöä" | LC_ALL=C awk ''{match($0,"//w+",a)}END{print a[0]}'' xyzv $ echo "xyzvöä" | LC_ALL=et_EE.utf8 awk ''{match($0,"//w+",a)}END{print a[0]}'' xyzvöä $ echo "xyzvöä" | LC_ALL=C awk ''{match($0,"[[:alpha:]]+",a)}END{print a[0]}'' xyzv $ echo "xyzvöä" | LC_ALL=et_EE.utf8 awk ''{match($0,"[[:alpha:]]+",a)}END{print a[0]}'' xyzvöä

grep (GNU grep 2.25)

$ echo xuzvöä | LC_ALL=C grep [a-z] xuzvöä $ echo xuzvöä | LC_ALL=et_EE.utf8 grep [a-z] xuzvöä $ echo xuzvöä | LC_ALL=C grep [[:alpha:]] xuzvöä $ echo xuzvöä | LC_ALL=et_EE.utf8 grep [[:alpha:]] xuzvöä $ echo xuzvöä | LC_ALL=C grep //w xuzvöä $ echo xuzvöä | LC_ALL=et_EE.utf8 grep //w xuzvöä


En los viejos días de Perl 3.0, todo era ASCII, y Perl lo reflejaba. /w significaba lo mismo que [0-9A-Z_a-z] . Y nos ha gustado!

Sin embargo, Perl ya no está vinculado a ASCII. Dejé de usar [az] un tiempo porque me gritaron cuando los programas que escribí no funcionaban con idiomas que no eran el inglés. Debes haber imaginado mi sorpresa como estadounidense al descubrir que hay al menos varios miles de personas en este mundo que no hablan inglés.

Perl tiene mejores formas de manejar [0-9A-Z_a-z] todos modos. Puede usar el conjunto [[:alnum:]] o simplemente usar /w que debería hacer lo correcto. Si solo debe tener caracteres en minúscula, puede usar [[:lower:]] lugar de [az] (que asume un tipo de idioma en inglés). (Perl hace todo lo posible para que [az] signifique solo los 26 caracteres a, b, c, ... z incluso en plataformas EBCDIC).

Si necesita especificar solo ASCII, puede agregar el calificador /a . Si te refieres a la configuración regional específica, debes compilar la expresión regular dentro del ámbito léxico de un ''uso de configuración regional''. (Evite el modificador / l, ya que solo se aplica al patrón de expresión regular, y nada más. Por ejemplo, en ''s / [[: lower:]] / / U $ & / lg'', el patrón se compila usando la configuración regional, pero el / U no lo está. Esto probablemente debería considerarse un error en Perl, pero es la forma en que funcionan las cosas actualmente. El modificador / l en realidad solo está destinado a la contabilidad interna, y no debe escribirse directamente.) En realidad, es mejor traducir los datos locales al ingresar al programa y volver a traducirlos en la salida, mientras se usa Unicode internamente. Si su configuración regional es una de las UTF-8 de nueva moda, hay disponible una nueva característica en 5.16 ''use locale ": not_characters"'' para permitir que las otras partes de su configuración regional funcionen sin problemas en Perl.

$word =~ /^[[:alnum:]]+$/ # $word contains only Posix alphanumeric characters. $word =~ /^[[:alnum:]]+$/a # $word contains only ASCII alphanumeric characters. { use locale; $word =~ /^[[:alnum:]]+$/;# $word contains only alphanum characters for your locale }

Ahora, ¿es esto un error? Si el programa no funciona como se esperaba, es un error simple y simple. Si realmente desea la secuencia ASCII, [az] , entonces el programador debería haber usado [[:lower:]] con el calificador /a . Si desea todos los posibles caracteres en minúscula, incluidos los de otros idiomas, simplemente debe usar [[:lower:]] .