Как я могу использовать grep, чтобы увидеть, совпадает ли мое слово в массиве со списком слов в словаре, и извлечь точное слово? - PullRequest
0 голосов
/ 01 октября 2009

Спасибо за ответы ... Я пробую разные возможности со всеми вашими ответами. одна вещь: я не мог бы быть намного яснее, задавая вопрос всем вам, т.е. Я применяю этот RE в моем локальном сценарии / символе (аналогично тибетскому сценарию), а не в английском слове.

foreach my $word (@list)
{
  if(grep(/$word/, $dict))       # i have dict in scalar ($dict)
       {
           print "Matched and Found\n";
        }
    else
      {
         print "Not Matched\n";
      }
}

Фокус состоит в том, чтобы извлечь одно точное слово. я попытался использовать / \ b $ word \ b / ..., который, кажется, не работает в нашем сценарии ... где наше слово состоит из мультислогов, а каждый слог разделен (.) (тибетский чег).

Дополнительная информация:

Для новичка наиболее сложной чертой тибетского предложения является отсутствие разделения между словами. ... Поскольку после слова нет пробела, читатель должен понять Каждое слово в зависимости от контекста и местоположения в предложении. Поиск этих двух букв в словаре может привести вас к мысли, что это предложение начинается со ссылки на поверхность земли. Тем не менее, оставшаяся часть предложения, его контекст и отсутствие активного соединительного падежа указывают на то, что эти две буквы сами по себе не слова, а слово «вчера». Из этого видно, что сначала полезно оценить предложение в целом, определив его различные элементы, а не переводя его слово в слово.

Акцент добавлен. Смотри http://www.learntibetan.net/grammar/sentence.htm

Ответы [ 10 ]

3 голосов
/ 02 октября 2009

Сохранение словаря в строке и использование grep для его поиска будет очень медленным для словаря любого размера. Рассматривали ли вы использование хэша для словаря? * 1001 Т.е. *

$dict = { word1 => 1, word2 => 1....... etc } # for example...

for my $word (@list) 
{ 
   if ($dict->{$word})
   {
      print "Matched\n";
   }
   else
   {
      print "Not matched\n";
   }
}

Обратите внимание, что я не рекомендую создавать хэш таким образом, это всего лишь пример, демонстрирующий использование хеша в качестве словаря, ключами которого являются слова, а значениями - постоянное «истинное» значение. Если для сопоставления необходимо учитывать регистр символов, слова в словаре должны быть строчными, прежде чем вставлять их в хеш, и слова $ в нижнем регистре перед поиском.

РЕДАКТИРОВАТЬ: Вот некоторый код для загрузки словаря из файла с одним словом в строке

open(FH,'dictionary.txt');
$dict = { map {chomp; $_,1} <FH> }
close(FH)

Пояснение:

  1. в контексте списка читает весь файл
  2. Функция карты оценивает блок (в скобках) для каждой строки
  3. Блок удаляет перевод строки и возвращает двухэлементный список содержащий слово и '1'
  4. Весь возвращаемый список используется для инициализировать хэш
  5. Ссылка на хеш хранится в $ ДИКТ
2 голосов
/ 02 октября 2009

Ваш синтаксис grep в порядке.

Хотя я чувствую себя обязанным прокомментировать ваш алгоритм. Это очень расточительно.

Вы перебираете @dict один раз для каждого слова в @list.

Было бы быстрее назначить один массив ключам хеша и выполнить поиск по хешу:

my %lut;
@lut{@list} = ();

for my $word ( @dict ) {
    print exists $lut{$word} ? "Matched and Found\n" : "Not Matched\n";
}

Поиск хеша происходит в постоянное время, и поэтому вместо вложенного цикла у вас есть плоский цикл. По мере того как ваши списки слов растут, различия в скорости должны становиться очевидными.

2 голосов
/ 01 октября 2009

Вместо написания собственного кода для сравнения каждого элемента @list с каждым элементом @dict, используйте модуль, который уже выполняет эту работу, например List :: Compare :

use strict;
use warnings;
use List::Compare;

my @dict = qw(apple banana orange grape pomegranate);
my @list = qw(banana giraffe pomegranate apple);

my $lc = List::Compare->new(\@dict, \@list);
my @intersection = $lc->get_intersection;

print "words found in the dictionary: " . join(', ', @intersection) . "\n";
2 голосов
/ 01 октября 2009

Я люблю

grep { $_ =~ /blah/} @foo

Это позволяет мне изменить условие позже, чем прямое

grep(/blah/, @foo)

Но я не вижу ничего плохого в вашем синтаксисе.

1 голос
/ 01 октября 2009

Я бы использовал для этого List::Util::first. Прекращает обработку списка после первого ответа. grep этого не сделает.

if( defined first { /$word/ } @list ) {
    print "Matched and Found\n";
}
else {
    print "Not Matched\n";
}
0 голосов
/ 08 декабря 2015

Вы можете использовать границу слова, чтобы соответствовать слову в словаре. (Слово окружено одним или несколькими пробелами, кроме начала и конца страницы).

Вы можете пойти с этим

$dict ="squirrel in my pocket ";

@list =(squirrel,in,me,poc);

foreach my $word (@list)
{
  if(grep(/\b$word\b/, $dict))       
  {
    print "\$word:$word  Matched with     \$dict :$dict \n";
  }
  else
  {
   print "\$word:$word  Not Matched with \$dict :$dict \n";
  }
}

Выход:

$word:squirrel  Matched     with  $dict :squirrel in my pocket
$word:in        Matched     with  $dict :squirrel in my pocket
$word:me        Not Matched with  $dict :squirrel in my pocket
$word:poc       Not Matched with  $dict :squirrel in my pocket
0 голосов
/ 02 октября 2009

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

Он использует File :: Slurp для эффективного удаления файла в виде списка строк, chomp s каждой строки и разбивает его, чтобы получить слово в качестве ключа и определение в качестве значения в хеше %dict.

Предполагается, что @words уже содержит отдельные слова, и слова не нужно идентифицировать из произвольного текста, такого как "a.a.b.a.b.b.a.a.b.a" (см. Мое замечание, указывающее, что слова не разделены на тибетском языке, только слоги).

Чтобы изменить код для чтения словаря из внешнего файла, замените \*DATA на имя файла.

#!/usr/bin/perl

use strict;
use warnings;

use File::Slurp;

my @words = qw( a b a.b b.a a.a b.a.b);

my %dict = map { chomp; split /\s*=\s*/ } read_file \*DATA;

for my $word ( @words ) {
    if ( defined(my $defn = $dict{$word}) ) {
        print "'$word' means $defn\n";
    }
    else {
        print "'$word' not found\n";
    }
}

__DATA__
a = Letter 1
b = Letter 2
a.b = Letter 1 and Letter 2
b.a = Letter 2 and Letter 1
a.b.a = Letter 1 and Letter 2 and Letter 1
b.a.b = Letter 2 and Letter 1 and Letter 2

Выход:

'a' means Letter 1
'b' means Letter 2
'a.b' means Letter 1 and Letter 2
'b.a' means Letter 2 and Letter 1
'a.a' not found
'b.a.b' means Letter 2 and Letter 1 and Letter 2
0 голосов
/ 02 октября 2009

В Perl 5.10 мы имеем умное сопоставление!

foreach my $word (@list) {
  say $word ~~ @dict ? 'Matched and Found' : 'Not Matched';
}
0 голосов
/ 01 октября 2009

В вашем синтаксисе нет ничего плохого. Это просто не очень Perlish. На самом деле, ваш код говорит: «Привет, у меня есть C-фон!». Таким образом, для начала я избавлюсь от паренов после grep.

Но то, что действительно нужно больше думать, это ваше регулярное выражение. Что если @list содержит «секс», а @dict содержит «Эссекс»? Я бы изменил это регулярное выражение на:

m/^$word$/i
0 голосов
/ 01 октября 2009

Это легко: нет ничего плохого. Я могу прекрасно запустить этот код в Perl, и он работает как задумано. Проблема должна быть где-то еще. Используете ли вы «использовать строгий»; вверху файла?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...