Perl:自定义排序顺序?

时间:2016-02-13 03:12:14

标签: arrays perl sorting

速记键盘具有特定顺序的键:STKPWHRAO *#EUFRPBLGTS。

我正在尝试输入$ word并确定其字母是否遵循此顺序,从左到右。

所以KAT是有效的,但FRAG不会,因为虽然F在右边的R之前,但它们不在A-之前。 TKPWAUL会起作用,但GAUL不会,因为-G不在A之前。键必须从左到右排序。

我被订单中出现两次的一些信件绊倒了。

非常感谢任何ieas!

2 个答案:

答案 0 :(得分:5)

你可以创建一个带有锚点的正则表达式来开始和结束字符串,并允许每个字符0或一次。这是一个例子:

sub match {
    my $yesno = $_[0] =~ /^S?T?K?P?W?H?R?A?O?\*?#?E?U?F?R?P?B?L?G?T?S?\.?$/g;
    print $_[0] . " " . ($yesno ? 'yes' : 'no') . "\n";
}
match 'KAT';
match 'FRAG';
match 'TKPWAUL';
match 'GAUL';

递送

KAT yes
FRAG no
TKPWAUL yes
GAUL no

您可以使用splitjoin等从列表中生成该正则表达式。

答案 1 :(得分:0)

这是一个简单的算法。这应该是有效的,如果需要也可以改进。

迭代单词中的字符,在参考序列中搜索每个字符。将序列中的匹配位置与前一个字符的位置进行比较。继续搜索所有匹配,因为序列中的某些字母重复。搜索使用index

sub accept_word {
    my ($refseq, $word) = @_; 
    my ($mark, $pos) = (0, 0); 
    foreach my $ch (split '', $word) {
        # search until position is >= $mark, or the word is bad 
        while ( ($pos = index($refseq, $ch, $pos)) != -1 ) { 
            $mark = $pos, last  if $pos >= $mark;
        }   
        return 0 if $pos < $mark;
    }   
    return 1;
}   
for my $word (qw(KAT FRAG TKPWAUL GAUL SAS)) {
    print "$word is " . (accept_word($refseq, $word) ? 'accepted' : 'rejected') . "\n";
}   

评论:

如果需要,这可以收紧很多。搜索可以大大优化,因为在开始和结束时只有'S'和'T'重复(见注释)。或者,可以通过首先查找序列中的字母数(例如通过('S' => 2, 'T' => 2, 'K' => 1)等)来优化它,以便index不会做不必要的工作。请参阅tba的评论,了解他与稍微紧张的版本的链接以及它与他发布的使用不同算法的正则表达式解决方案之间的基准。

详细说明此逐步解决方案。用字符迭代你的单词,每个人做以下事情:

遍历参考序列,一旦找到匹配,就在序列中记录其数字索引。在第一遍(第一个单词字符),这将成为最高位置,比如$mark

对于剩余的迭代,需要注意,因为引用序列具有重复的字符。 (感谢tba发表评论。)当发现char在序列中匹配时,匹配的索引与$mark进行比较,如果是>=,我们重置{ {1}}然后转到下一个字符。如果位置为$mark,则搜索和比较将继续,直到找到< $mark或序列耗尽,此时该词被丢弃(char位于前一个词的左侧)。改进:从>=开始搜索,如果找到匹配,请重置$mark并移至下一个字符,否则将丢弃该字(在上面的代码中通过$mark完成)。当你匹配单词中的字符时,你正在爬上参考序列并记住你得到了多远。

这样,单词将被映射到基于引用字符串的非递减数字序列,或被丢弃。在上面的代码中,如果需要,可以记录数字编码。