use Unicode::Normalize;
($gutted = NFD($string)) =~ s/pM//g;
However, this is almost always the wrong(est) thing to do. What are you going to do about
?var Arnfj?re
?enan ?ubovi?
King Henry Ⅷ
Carlos Ⅴo, el Emperador
Just embrace Unicode. The correct way to match things with or without diacritics is to instantiate a Unicode::Collator
object with the strength set to ignore diacritics. Then just call the cmp
or eq
methods.
EDIT
This is how you should go about these things. Witness:
?La Alberguería de Arga?án? sí tiene /AN/ en un par de sitios ?a?? y ?án?
sí tiene /AL/ en un solo sitio ?Al?
?Bóveda del Río Almar? sí tiene /AL/ en un solo sitio ?Al?
?Cabezón de Liébana? sí tiene /AN/ en un solo sitio ?an?
sí tiene /ON/ en un solo sitio ?ón?
?Do?a Mencía? sí tiene /EN/ en un solo sitio ?en?
sí tiene /ON/ en un solo sitio ?o??
?Gallegos de Arga?án? sí tiene /AN/ en un par de sitios ?a?? y ?án?
sí tiene /AL/ en un solo sitio ?al?
?Gri?ón? sí tiene /IN/ en un solo sitio ?i??
sí tiene /ON/ en un solo sitio ?ón?
?Logro?o? sí tiene /ON/ en un solo sitio ?o??
?Lli?à d’Amunt? sí tiene /UN/ en un solo sitio ?un?
?Madro?al? sí tiene /ON/ en un solo sitio ?o??
sí tiene /AL/ en un solo sitio ?al?
?Mantilla? sí tiene /AN/ en un solo sitio ?an?
?Ma?ón? sí tiene /AN/ en un solo sitio ?a??
sí tiene /ON/ en un solo sitio ?ón?
?Matilla de los Ca?os del Río? sí tiene /AN/ en un solo sitio ?a??
?Montalbán de Córdoba? sí tiene /AN/ en un solo sitio ?án?
sí tiene /ON/ en un solo sitio ?on?
sí tiene /AL/ en un solo sitio ?al?
?La Pe?a? sí tiene /EN/ en un solo sitio ?e??
?Pi?uécar–Gandullas? sí tiene /AN/ en un solo sitio ?an?
sí tiene /IN/ en un solo sitio ?i??
?A Pobra do Carami?al? sí tiene /IN/ en un solo sitio ?i??
sí tiene /AL/ en un solo sitio ?al?
?Prats de Llu?anès? sí tiene /AN/ en un solo sitio ?an?
?Ribamontán al Monte? sí tiene /AN/ en un solo sitio ?án?
sí tiene /ON/ en un par de sitios ?on? y ?on?
sí tiene /AL/ en un solo sitio ?al?
?La Roca del Vallès? sí tiene /AL/ en un solo sitio ?al?
?San Martín del Casta?ar? sí tiene /AN/ en un par de sitios ?an? y ?a??
sí tiene /IN/ en un solo sitio ?ín?
?Santa Eulàlia de Ron?ana? sí tiene /AN/ en un par de sitios ?an? y ?an?
sí tiene /ON/ en un solo sitio ?on?
sí tiene /AL/ en un solo sitio ?àl?
?Santa María de Cayón? sí tiene /AN/ en un solo sitio ?an?
sí tiene /ON/ en un solo sitio ?ón?
?Valverde de Alcalá? sí tiene /AL/ en 3 sitios ?al?, ?Al? y ?al?
?Villar de Arga?án? sí tiene /AN/ en un par de sitios ?a?? y ?án?
And here is the code that generates that.
#!/usr/bin/env perl
#
# búsqueda-libre:
#
# Cómo se debiera ordenar y buscar palabras en Unicode
# que pueden llevarse marcas diacríticas (o no) sin que
# éstas afecten la búsqueda. También cómo cambiar el
# el orden para que no cuente con articulos al principio
# del los nombres, como se hace con los títulos de libros &c.
#
# Tom Christiansen <[email protected]>
# Fri Mar 4 21:06:35 MST 2011
#
#############################################
use utf8;
use 5.10.1;
use strict;
use warnings; # FATAL => "all";
use autodie;
use charnames qw< :full >;
use List::Util qw< max first >;
use Unicode::Collate;
my $INCLUíR_NINGUNOS = 0;
my $SI_IMPORTAN_MARCAS_DIACRíTICAS = 0;
sub sí_ó_no(_) { $_[0] ? "sí" : "no" }
sub encomillar(_) {
return join $_[0] =>
"N{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}",
"N{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}",
;
}
binmode(STDOUT, ":utf8");
# ésta está demasiada larga para la pantalla. :(
#
# La Ciudad de Nuestra Se?ora la Reina de Los ángeles de Porciúncula, California Alta
#
my @ciudades_espa?olas = ordenar_a_la_espa?ola(<<'LA_úLTIMA' =~ /S.*S/g);
Santa Eulàlia de Ron?ana
Ma?ón
A Pobra do Carami?al
La Alberguería de Arga?án
Logro?o
La Puebla del Río
Villar de Arga?án
Pi?uécar–Gandullas
Mantilla
Gallegos de Arga?án
Madro?al
Gri?ón
Lli?à d’Amunt
Valverde de Alcalá
Montalbán de Córdoba
San Martín del Casta?ar
La Pe?a
Cabezón de Liébana
Do?a Mencía
Santa María de Cayón
Bóveda del Río Almar
La Roca del Vallès
Matilla de los Ca?os del Río
Prats de Llu?anès
Ribamontán al Monte
LA_úLTIMA
my $cmáx = -(2 + max map { length } @ciudades_espa?olas);
my @búsquedas = < {A,E,I,O,U}N AL >;
my $bmáx = -(2 + max map { length } @búsquedas);
my $ordenador = new Unicode::Collate::
level => $SI_IMPORTAN_MARCAS_DIACRíTICAS ? 2 : 1,
## variable => "non-ignorable", # blanked, non-ignorable, shifted, shift-trimmed
normalization => undef,
;
for my $aldea (@ciudades_espa?olas) {
my $déjà_imprimée;
for my $búsqueda (@búsquedas) {
my @resultados = $ordenador->gmatch($aldea, $búsqueda);
next unless @resultados || $INCLUíR_NINGUNOS;
printf qq(%*s %s tiene %*s en %17s %s
),
$cmáx => !$déjà_imprimée++ && encomillar($aldea),
sí_ó_no(@resultados),
$bmáx => "/$búsqueda/",
cuántos_sitios(@resultados),
enfilar(@resultados);
}
}
sub cuántos_sitios {
my @lista = @_;
my $cantidad = @_;
given ($cantidad) {
when (0) { return "ningún sitio" }
when (1) { return "un solo sitio" }
when (2) { return "un par de sitios" }
default { return "$cantidad sitios" }
}
}
sub enfilar {
my @lista = map { encomillar } @_;
my $separador = "N{COMMA}";
$separador = "N{SEMICOLON}" if first { /$separador/ } @lista;
$separador .= "N{SPACE}";
given (scalar @lista) {
when (0) { return "" }
when (1) { return "@lista" }
when (2) { return join " y " => @lista }
default { return
join($separador => @lista[ 0 .. ($#lista-1) ])
. " y $lista[$#lista]";
}
}
}
###################################################
# Para ordenar los elementos de la lista
# en el estilo tradicional del castellano.
#
# Tenemos en cuenta que sí pueden aparecerse nombres
# de ciudades que no son nombres sólo castellanos
# sino tambíen catalanes y gallegos — y tal vez más,
# como en asturianu or aranés, pero no he pensado
# mucho es estos.
###################################################
sub ordenar_a_la_espa?ola {
my @lista = @_;
state $ordenador_a_la_espa?ola = new Unicode::Collate::
# Si se tuviese Unicode::Collate::Locale con "es__traditional",
# no haría falta este primer lío con su entrada especial,
# con la excepción de la c-cedilla, la cual aquí se ordena
# como si fuese catalán, no castellano.
# Vamos a meter las nuevas entradas después de éstas,
# que son copiadas del DUCET v6.0.0. Tuve que cambiar unos
# valores que tenía este código desde otra versión anterior.
#
# 0043 ; [.123D.0020.0008.0043] # LATIN CAPITAL LETTER C
# 00C7 ; [.123D.0020.0008.0043][.0000.0056.0002.0327] # LATIN CAPITAL LETTER C WITH CEDILLA; QQCM
# 004C ; [.1330.0020.0008.004C] # LATIN CAPITAL LETTER L
# 004E ; [.136D.0020.0008.004E] # LATIN CAPITAL LETTER N
# 00D1 ; [.136D.0020.0008.004E][.0000.004E.0002.0303] # LATIN CAPITAL LETTER N WITH TILDE; QQCM
entry => <<'SALIDA', # :)
00E7 ; [.123E.0020.0002.0327] # c-cedilla
0063 0327 ; [.123E.0020.0002.0327] # c-cedilla
00C7 ; [.123E.0020.0002.0327] # C-cedilla
0043 0327 ; [.123E.0020.0002.0327] # C-cedilla
0063 0068 ; [.123F.0020.0002.0043] # ch
0043 0068 ; [.123F.0020.0007.0043] # Ch
0043 0048 ; [.123F.0020.0008.0043] # CH
006C 006C ; [.1331.0020.0002.004C] # ll
004C 006C ; [.1331.0020.0007.004C] # Ll
004C 004C ; [.1331.0020.0008.004C] # LL
00F1 ; [.136E.0020.0002.0303] # n-tilde
006E 0303 ; [.136E.0020.0002.0303] # n-tilde
00D1 ; [.136E.0020.0008.0303] # N-tilde
004E 0303 ; [.136E.0020.0008.0303] # N-tilde
SALIDA
upper_before_lower => 1,
normalization => "NFKD", # ?Y porqué no?
preprocess => sub {
my $_ = shift;
###
# no incluye los artículos definitivos ni indefinitivos
###
s/^Lp{QMARK}//; # puede encontrarse en el catalán
s{ ^
(?: # del castellano
El
| Los
| La
| Las
# del catalán
| Els
| Les
| Sa
| Es
# del gallego
| O
| Os
| A
| As
)
h +
}{}x;
# Luego quita las palabras no-importantes interiores.
s/[dl]p{QMARK}//g; # del catalán
s{
(?:
el | los | la | las | de | del | y # ES
| els | les | i | sa | es | dels # CA
| o | os | a | as | do | da | dos | das # GAL
)
}{}gx;
return $_;
}, # fin de rutina preprocesadora
## ?Fijaos que no borréis esta marca!
## Este punto y coma marca el fin
## de los argumentos del constructor
## empezado ya muchas lineas arriba.
## ?
; # ←←← Sí, ése — dejadlo en paz o muy tristes os quedaréis.
## ?
return $ordenador_a_la_espa?ola->sort(@lista);
}