2013-04-11 2 views
2

У меня есть проблема, я надеюсь, кто-то может помочь с (значительно упрощена в целях объяснения, что я пытаюсь сделать) ...Perl - Проверьте, если какие-либо элементы в каждом другом массиве соответствует переменной

I есть три различных массивов:

my @array1 = ("DOG","CAT","HAMSTER"); 
my @array2 = ("DONKEY","FOX","PIG", "HORSE"); 
my @array3 = ("RHINO","LION","ELEPHANT"); 

у меня также есть переменная, которая содержит контент с веб-страницы (с помощью WWW :: Mechanize):

my $variable = $r->content; 

Теперь я хочу, чтобы увидеть, если какой-либо из элементов в каждый из массивов находятся в переменной, и если да, какой массив она исходит от:

например

if ($variable =~ (any of the elements in @array1)) { 
    print "FOUND IN ARRAY1"; 
} elsif ($variable =~ (any of the elements in @array2)) { 
    print "FOUND IN ARRAY2"; 
} elsif ($variable =~ (any of the elements in @array3)) { 
    print "FOUND IN ARRAY3"; 
} 

Что такое лучший способ пойти об этом, используя массивы и переборе каждого элемента массивы? Есть ли лучший способ сделать это?

ваша помощь очень ценится, благодаря

ответ

7

Вы можете сделать регулярное выражение из элементов массива, но вы, скорее всего, захотите отключить мета-символы и убедитесь, что вы не получите частичные совпадения:

my $rx = join('\b|\b', map quotemeta, @array1); 

if ($variable =~ /\b$rx\b/) { 
    print "matched array 1\n"; 
} 

Если вы хотите получите частичные совпадения, например FOXY, просто удалите все последовательности \b.

Демонстрация:

use strict; 
use warnings; 

my @array1 = ("DOG","CAT","HAMSTER"); 
my @array2 = ("DONKEY","FOX","PIG", "HORSE"); 
my @array3 = ("RHINO","LION","ELEPHANT"); 

my %checks = (
    array1 => join('\b|\b', map quotemeta, @array1), 
    array2 => join('\b|\b', map quotemeta, @array2), 
    array3 => join('\b|\b', map quotemeta, @array3), 
); 

while (<DATA>) { 
    chomp; 
    print "The string: '$_'\n"; 
    for my $key (sort keys %checks) { 
     print "\t"; 
     if (/\b$checks{$key}\b/) { 
      print "does"; 
     } else { 
      print "does not"; 
     } 
     print " match $key\n"; 
    } 
} 

__DATA__ 
A DOG ATE MY RHINO 
A FOXY HORSEY 

Выход:

The string: 'A DOG ATE MY RHINO' 
     does match array1 
     does not match array2 
     does match array3 
The string: 'A FOXY HORSEY' 
     does not match array1 
     does not match array2 
     does not match array3 
+0

, положив \ b в соединении, отключит сопоставление aho-corasick, я полагаю; просто сделайте '\ b (?: $ rx) \ b' вместо – ysth

+0

@ysth Ахо какой? Что это на английском? – TLP

+0

алгоритм соответствия, который perl иногда будет использовать для | чередующиеся фиксированные строки; без него, в основном каждый | альтернатива будет проверяться в каждой позиции в строке до тех пор, пока она не будет совпадать. http://en.wikipedia.org/wiki/Aho-Corasick – ysth

0

EDIT: Я думаю, что вы могли бы использовать map функцию языка Perl, что-то вроде этого:

@a1matches = map { $variable =~ /$_/ ? $_ :(); } @array1; 
print "FOUND IN ARRAY1\n" if $#a1matches >= 0; 

@a2matches = map { $variable =~ /$_/ ? $_ :(); } @array2; 
print "FOUND IN ARRAY2\n" if $#a2matches >= 0; 

@a3matches = map { $variable =~ /$_/ ? $_ :(); } @array3; 
print "FOUND IN ARRAY3\n" if $#a3matches >= 0; 

Весело побочный эффект заключается в том, что @a1matches содержат элементы @array1, что были в $variable.

+1

Это никогда не вернет false, если только '$ variable' содержит ложное значение. А также ваш чек отменяется. – TLP

+2

У вас есть это в обратном порядке. Он хочет узнать, находится ли какой-либо элемент массива в '$ variable', а не' 'переменная' 'находится в любом из массивов. –

+0

Упс. Позвольте мне подумать и отредактировать ответ здесь. –

0

Я предполагаю, что $variable не является массивом, и в этом случае используйте заявление .

foreach my $item (@array1) { 
    if ($item eq $variable) { 
     print "FOUND IN ARRAY1"; 
    } 
} 

и повторить выше для каждого массива, т.е. array2, array3 ...

2
my $re1 = join '|', @array1; 
say "found in array 1" if $variable =~ /$re1/; 

Повторите для каждого дополнительного массива (или использовать массив регулярных выражений и массив массивов терминов).

+0

Что делать, если одно из содержимого @array имеет специальные символы, например '| «? – imran

+0

@imran: В этом случае 'my $ re1 = join '|', map {" \ Q $ _ \ E "} @ array1;' –

+1

Вам также нужно беспокоиться о частичных совпадениях. – TLP

0

Regexp::Assemble может оказаться полезным, если вы хотите использовать модуль. Он позволяет собирать строки регулярных выражений в одно регулярное выражение, соответствующее всем отдельным регулярным выражениям.

1

Прежде всего, если When you find yourself adding an integer suffix to variable names, think I should have used an array.

Поэтому, прежде всего, я собираюсь положить слова в массив arrayrefs. Это поможет определить, откуда взялось соответствующее слово.

Во-вторых, я собираюсь использовать Regex::PreSuf, чтобы сделать шаблон из каждого списка слов, потому что я всегда забываю правильный способ сделать это.

Третье примечание, которое using \b in regex patterns can lead to surprising results. Поэтому вместо этого я собираюсь разделить содержимое на отдельные последовательности из \w символов.

В-четвертых, вы говорите: «У меня также есть переменная, содержащая содержимое с веб-страницы (с использованием WWW :: Mechanize)». Вы хотите совместить слова в комментариях? В атрибутах title? Если вы этого не сделаете, вы должны проанализировать HTML-документ либо для извлечения полного текстового текста, либо для ограничения соответствия внутри определенного элемента или набора элементов.

Затем grep из списка слов в тексте, которые находятся в слове и сопоставляют их со словом, который они сопоставляли.

#!/usr/bin/env perl 

use strict; use warnings; 

use Regex::PreSuf qw(presuf); 

my @wordsets = (
    [ qw(DOG CAT HAMSTER) ], 
    [ qw(DONKEY FOX PIG HORSE) ], 
    [ qw(RHINO LION ELEPHANT) ], 
); 

my @patterns = map { 
    my $pat = presuf(@$_); 
    qr/\A($pat)\z/; 
} @wordsets; 

my $content = q{Lorem ipsum dolor sit amet, consectetur adipisicing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim 
ad minim veniam, quis ELEPHANT exercitation ullamco laboris nisi ut aliquip 
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in HAMSTER 
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat 
cupidatat non proident, sunt in DONKEY qui officia deserunt mollit anim id 
est laborum.}; 

my @contents = split /\W+/, $content; 

use YAML; 
print Dump [ 
    map { 
     my $i = $_; 
     map +{$_ => $i }, 
     grep { $_ =~ $patterns[$i] } @contents 
    } 0 .. $#patterns 
]; 

Здесь grep { $_ =~ $patterns[$i] } @contents извлекает слова из @contents, которые находятся в данной wordset. Затем map +{$_ => $i } сопоставляет эти слова с набором слов, из которого они пришли. Внешний map просто перебирает каждый шаблон набора слов.

Выход:

--- 
- HAMSTER: 0 
- DONKEY: 1 
- ELEPHANT: 2

То есть, вы получите список hashrefs где ключ в каждом hashref это слово, которое было найдено и значение является wordset, что соответствует.