【问题标题】:How do I search for words that begins and ends with other words from the same array?如何从同一数组中搜索以其他单词开头和结尾的单词?
【发布时间】:2011-04-06 13:43:24
【问题描述】:

我在一个数组中有很长的单词列表。有的短,有的长。我想过滤掉那些以数组中的一个单词开头的单词(这个“前缀”单词的长度可以设置为,比如说,3个字符)并且同时以它的一个单词结尾。

假设第一个词是“车棚”。现在,如果数组中也存在“car”和“port”,我会得到一个匹配项。但如果这个词是“carlsberg”,我就找不到匹配项(因为“lsberg”可能不是数组中的现有词)。

结果最好以“前缀词、后缀词、整个词”的形式出现。

我会考虑使用任何可以让我做到这一点的语言,尽管我自己主要是一个 JavaScript 人。

【问题讨论】:

  • 您自己尝试过吗?你能发布你到目前为止所拥有的吗?谢谢。
  • 您说“任何语言”——这是针对 Web 应用程序的吗?如果是这样,您使用的是什么服务器技术,我们是否可以访问 PHP/PERL/ASP?如果这只是一个页面重新加载,你可能会在服务器端获得更好的性能。如果您可以提供更多信息,我会尽力为您提供解决方案:)
  • 这将是一个“运行一次”的事情来生成一个新文件。我昨晚深夜只尝试了一些正则表达式,但想与你们核实是否有任何优雅的解决方案,无论语言如何(我知道有些语言比其他语言更适合不同类型的任务)。到目前为止的(快速!)响应让我们感到惊讶,非常感谢!

标签: javascript regex arrays perl string


【解决方案1】:

我想知道trie 是否有帮助,请参阅What is the most common use of the “trie” data structure?

Perl 有几个模块可以构建它们:

其他听起来有点像它的起点的东西是Ruby's Abbrev 模块:

#!/usr/bin/env ruby

require 'abbrev'
require 'pp'

pp %w[car port carport carlsberg].abbrev
# >> {"por"=>"port",
# >>  "po"=>"port",
# >>  "p"=>"port",
# >>  "carpor"=>"carport",
# >>  "carpo"=>"carport",
# >>  "carp"=>"carport",
# >>  "carlsber"=>"carlsberg",
# >>  "carlsbe"=>"carlsberg",
# >>  "carlsb"=>"carlsberg",
# >>  "carls"=>"carlsberg",
# >>  "carl"=>"carlsberg",
# >>  "car"=>"car",
# >>  "port"=>"port",
# >>  "carport"=>"carport",
# >>  "carlsberg"=>"carlsberg"}

【讨论】:

    【解决方案2】:

    好吧,JavaScript 中的幼稚实现应该是这样的:

    function triples(words) { 
        var result = new Array();
        for(var i=0; i<words.length; i++) {
            for(var j=0; j<words.length; j++) {
                var k = words.indexOf(words[i] + words[j]);
                if(k != -1) {
                    result.push([words[i], words[j], words[k]]);
                }
            }
        } 
        return result;
    }
    

    当前形式的函数需要所有单词的数组作为参数,并返回一个包含找到的单词三元组的数组数组(第一个元素是前缀,第二个元素是后缀,第三个元素是组合词)。

    【讨论】:

      【解决方案3】:

      类似这样的:

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      my @candidates=qw( carport Carsburg butterfly 
                      buttercup Christmas wishlist carpface flyface buttface);
      my @arr=<DATA>;
      chomp @arr;
      
      for my $i (3..6) {
          foreach my $j (@candidates) {
              my ($fp,$lp)=($1,$2) if ($j=~/(^.{$i})(.*$)/);
              if($fp && $lp) {
                  my @hit1=grep(/^$fp/,@arr);
                  my @hit2=grep(/$lp$/,@arr);
                  print "candidate: $j\n start= @hit1 end= @hit2\n=====\n" 
                      if (scalar @hit1 && scalar @hit2);
              }
          }
      }
      
      __DATA__
      car
      port
      wish
      list
      Christ
      mas
      butter
      cup
      fly
      face
      butt
      

      输出:

      candidate: carport
       start= car end= port
      =====
      candidate: flyface
       start= fly end= face
      =====
      candidate: wishlist
       start= wish end= list
      =====
      candidate: buttface
       start= butter butt end= face
      =====
      candidate: butterfly
       start= butter end= fly
      =====
      candidate: buttercup
       start= butter end= cup
      =====
      candidate: Christmas
       start= Christ end= mas
      

      【讨论】:

      • 在该列表中包含“carport”(和其他“组合”词)虽然会给我“end = carport port”,但我认为你接近我所追求的。也许过滤掉具有多个开始和结束的匹配?我正在考虑在大量文本上使用这个过滤器,甚至可能是某种字典,所以我认为每个起始词无论如何都必须出现?
      • 我不确定我是否理解。您是说您在__DATA 下的列表中添加了“车棚”吗?如果您希望这种类型的过滤基于单个列表而不是两个(我编写它的方式),那么逻辑会略有不同。
      • 抱歉回复晚了.. 是的,一份清单就是我的目标。 indata 可能是某种词汇表,用于查找由列表中的其他单词组成的单词。
      【解决方案4】:

      这是一个 Perl 解决方案,O(n + 2m)

      use warnings;
      use strict;
      use Data::Dumper;
      
      my @words = qw(car carport carlsberg cartographer airport photographer);
      
      my @ends  = qw(car port air grapher);
      
      my $ends_re = join '|' => @ends;
      
      my @matches = map {/^($ends_re).*($ends_re)$/ ? [$1, $_, $2] : ()} @words;
      
      print Dumper \@matches;
      

      打印:

      $VAR1 = [
            [
              'car',
              'carport',
              'port'
            ],
            [
              'car',
              'cartographer',
              'grapher'
            ],
            [
              'air',
              'airport',
              'port'
            ]
          ];
      

      【讨论】:

        【解决方案5】:

        我会这样做:

        <?php
        
            $words = array('experts', 'exchange', 'expert', 'sexchange');
        
            // build trie
            $t = array();
            foreach ($words as $word)
            {
                $n = &$t;
                for ($i = 0; $i < strlen($word); ++$i)
                {
                    $c = $word[$i];
        
                    if (!isset($n[$c])) $n[$c] = array();
        
                    $n = &$n[$c];
                }
        
                $n['.'] = true;
            }
        
            $word = 'expertsexchange';
        
            $n = $t;
            for ($i = 0; $i < strlen($word); ++$i)
            {
                $c = $word[$i];
        
                if (isset($n['.']))
                {
                    $o = $t;
                    for ($j = $i; $j < strlen($word); ++$j)
                    {
                        $d = $word[$j];
                        if (!isset($o[$d])) break;
                        $o = $o[$d];                    
                    }
        
                    # found match
                    if ($j == strlen($word) && isset($o['.']))
                    {
                        echo substr($word, 0, $i).",".substr($word,$i).",".$word."\n";
                    }
                }
        
                if (isset($n[$c]))
                {
                    $n = $n[$c];
                }
                else
                    break;
            }
        ?>
        
        Results:
        
        expert,sexchange,expertsexchange
        experts,exchange,expertsexchange
        

        我是在现场写的,所以它可能不会完全正确。但是这个想法是建立一个前缀树并遍历它。每次找到前缀(以“.”表示)时,从树的顶部再次继续,看看是否可以从该点找到后缀。这假设您不需要前缀和后缀之间的任何内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-06-29
          • 1970-01-01
          • 2019-12-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-24
          相关资源
          最近更新 更多