2013-05-28 47 views
3

[perl的5.8.8]的Perl:如何從一個編號序列使緊湊的名字

我有這樣的東西的名稱序列:

names='foobar1304,foobar1305,foobar1306,foobar1307' 

其中姓名用連續串唯一的不同在名字的某處數字。任何序列中的數字串都具有相同的長度,並且數字串形成沒有跳過的連續數字序列,例如, 003,004,005

我想要一個緊湊表示,如:

compact_name='foobar1304-7' 

(緊湊的形式只是一個名字,所以它的確切形式是可以商量) 有通常只有< 10的事情,雖然有些組可能跨越十年,例如

'foobaz2205-11' 

有沒有一些簡潔的方法在perl中做到這一點?我不是一個大的Perl黑客,所以會有點溫柔......

積分爲處理嵌入式序列,如:

names='foobar33-pqq,foobar34-pqq,foobar35-pqq' 

理想的腳本將整齊地回落到'firstname2301-lastname9922'的情況下,它可以」 t在名稱中標識一個序列。

+2

此問題未指定。你需要提出一套處理所有可能輸入的規則。對於你的最後一個例子,隱含的簡化'foobar33-35-pqq'可能在上下文中變得模糊不清。在Perl的正則表達式能力下,提取數字和摺疊序列的基本思想非常簡單,但是更大的問題是決定你真正想要做什麼。 –

+0

固定,我想。我沒有看到'foobar33-35-pqq'中的含糊不清。注意我指定的差異是'** a **連續的數字串'。如果名稱中有多個數字串,那麼我就保釋。 –

+0

我想你想要的是將字符串拆分成一個數組('@list = split(「,」,$ names)'或類似的東西),然後找到[最長的公共前綴](http://stackoverflow.com/questions/9114402/regexp-finding-longest-common-prefix-of-two-strings)這些單詞在數組中。獎金分數用於查找最長的通用後綴。所以你把單詞分成前綴,變量部分和後綴。那麼你的答案是「$ prefix $ varFirst」。 「 - 」。 「$ varLast $後綴」。那個聽起來是對的嗎? –

回答

2

我不知道我得到了你的規範,但它的工作原理莫名其妙:

#!/usr/bin/perl 
use warnings; 
use strict; 

use Test::More; 

sub compact { 
    my $string = shift; 
    my ($name, $value) = split /=/, $string; 

    $name =~ s/s$// or die "Cannot create compact name for $name.\n"; #/ SO hilite bug 
    $name = 'compact_' . $name; 

    $value =~ s/^'|'$//g;            #/ SO hilite bug 
    my @values = split /,/, $value;         #/ SO hilite bug 
    my ($prefix, $first, $suffix) = $values[0] =~ /^(.+?)([0-9]+)(.*)$/; 

    my $last = $first + $#values; 
    my $same = 0; 
    $same++ while substr($first, 0, $same) eq substr($last, 0, $same); 
    $last = substr $last, $same - 1; 

    for my $i ($first .. $first + $#values) { 
     $values[$i - $first] eq ($prefix . $i . $suffix) 
      or die "Invalid sequence at $values[$i-$first].\n"; 
    } 
    return "$name='$prefix$first-$last$suffix'"; 
} 


is(compact("names='foobar1304,foobar1305,foobar1306,foobar1307'"), 
    "compact_name='foobar1304-7'"); 

is(compact("names='foobaz2205,foobaz2206,foobaz2207,foobaz2208,foobaz2209,foobaz2210,foobaz2211'"), 
    "compact_name='foobaz2205-11'"); 

is(compact("names='foobar33-pqq,foobar34-pqq,foobar35-pqq'"), 
    "compact_name='foobar33-5-pqq'"); 

done_testing(); 
1

有人肯定會發佈一個更優雅的解決方案,但以下

use strict; 
use warnings; 

my $names='foobar1308-xy,foobar1309-xy,foobar1310-xy,foobar1311-xy'; 
my @names = split /,/,$names; 

my $pfx = lcp(@names); 

my @nums = map { m/$pfx(\d*)/; $1 } @names; 
my $first=shift @nums; 
my $last = pop @nums; 
my $suf=$names[0]; 
$suf =~ s/$pfx\d*//; 

print "$pfx\{$first-$last}$suf\n"; 

#https://gist.github.com/3309172 
sub lcp { 
    my $match = shift; 
    substr($match, (($match^$_) =~ /^\0*/, $+[0])) = '' for @_; 
    $match; 
} 

打印:

foobar13{08-11}-xy