用户输入一组带有重音和波浪号的名称:
Renato Núñez, David DeJesús, and Edwin Encarnación
我的数据库为这些人设置了英文名称
@names = ('Renato Nunez','David DeJesus','Edwin Encarnacion');
我希望对这些名称进行正则表达式匹配。
$string = "Renato Núñez, David DeJesús, and Edwin Encarnación";
foreach my $name (@names) {
print "found:$name\n" if ($name =~ /$string/);
}
如目前所示,我没有比赛。
我尝试了这个,但它没有用。
$string = "Renato Núñez, David DeJesús, and Edwin Encarnación";
foreach my $name (@names) {
$name =~ s|a|[áa]|;
$name =~ s|e|[ée]|;
$name =~ s|i|[íi]|;
$name =~ s|o|[óo]|;
$name =~ s|u|[úu]|;
$name =~ s|n|[ñn]|;
# Originally: print "found:$name\n" if ($name =~ /$string/);
# Corrected to:
print "found:$name\n" if ($string =~ /$name/);
}
编辑:抱歉,我在最后一行收到了$ name和$ string。
有什么建议吗?
答案 0 :(得分:7)
use Unicode::Normalize;
($gutted = NFD($string)) =~ s/pM//g;
然而,这几乎总是错误的(est)要做的事情。你打算怎么办
Ævar Arnfjörð
Dženan Ljubović
King Henry Ⅷ
Carlos Ⅴº, el Emperador
只需拥抱Unicode。 使用或不使用变音符号匹配事物的正确方法是实例化Unicode::Collator
对象,其强度设置为忽略变音符号。然后,只需调用cmp
或eq
方法。
这个就是你应该如何处理这些事情。证人:
«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»
以下是生成该代码的代码。
#!/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 <tchrist@perl.com>
# 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\n),
$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/^L\p{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/\b[dl]\p{QMARK}//g; # del catalán
s{
\b
(?:
el | los | la | las | de | del | y # ES
| els | les | i | sa | es | dels # CA
| o | os | a | as | do | da | dos | das # GAL
)
\b
}{}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);
}
答案 1 :(得分:2)
谷歌搜索它,我发现问题很常见(我使用查询“perl remove diacritic”)。请记住,它不是一个“精确”的科学(删除变音符号和英文化文本)。这里有一些链接:
http://www.ahinea.com/en/tech/accented-translate.html
http://search.cpan.org/~wollmers/Text-Undiacritic-0.02/lib/Text/Undiacritic.pm
http://search.cpan.org/~ldachary/Text-Unaccent-1.08/Unaccent.pm
作为一个建议,快速肮脏的方法:
\p{M}
(它将找到所有标记)我无法帮助你,因为我多年没有在Perl中编程。
答案 2 :(得分:1)
似乎你交换了参数。 你输入
$name =~ s|a|[áa]|;
试图用“[áa]”替换模式“a” 试试
$name =~ s|[áa]|a|;
交换比赛,它会起作用。
$string = "Renato Núñez, David DeJesús, and Edwin Encarnación";
foreach my $name (@names) {
print "found:$name\n" if ($string =~ /$name/);
}
答案 3 :(得分:1)
我相信你正在使用字符串“RenatoNúñez,DavidDeJesús和EdwinEncarnación”作为正则表达式
如果我理解正确,你试图匹配短语“RenatoNúñez,DavidDeJesús和EdwinEncarnación”中的每个名字。
如果是这种情况,那么您需要写:$string =~ /$name/ instead of $name =~ /$string/
答案 4 :(得分:1)
这可能更符合您的尝试。
use strict;
use warnings;
my @AngloNames = ('Renato Nunez','David DeJesus','Edwin Encarnacion');
my @AngEthRx;
for my $val (@AngloNames) {
$_ = $val;
s/a/[áa]/g;
s/e/[ée]/g;
s/i/[íi]/g;
s/o/[óo]/g;
s/u/[úu]/g;
s/n/[ñn]/g;
push @AngEthRx, $_;
}
# User input query string ...
my $AngEthQuery = "Renato Núñez, David DeJesús, and Edwin Encarnación";
for my $i (0 .. $#AngEthRx) {
if ( $AngEthQuery =~ /($AngEthRx[$i])/ ) {
print "found: $AngloNames[$i] ~ $1\n";
}
}
出
found: Renato Nunez ~ Renato Núñez
found: David DeJesus ~ David DeJesús
found: Edwin Encarnacion ~ Edwin Encarnación