2013-05-28 5 views
3

[펄 5.8.8]펄 : 번호가 매겨진 순서에서 컴팩트 이름을 만드는 방법

내가 좋아하는 것들의 이름의 순서가 : 이름이 연속 된 문자열 만 다른

names='foobar1304,foobar1305,foobar1306,foobar1307' 

을 이름의 어딘가에. 모든 시퀀스의 숫자 문자열은 모두 같은 길이이며 숫자 문자열은 건너 뛰기가없는 연속 숫자 시퀀스를 형성합니다 (예 : 003,004,005. 일부 세트에 걸칠 수도 있지만,

compact_name='foobar1304-7' 

(소형 폼 그냥 이름이고, 그래서 정확한 형식은 협상이다입니다.) 보통 < 10 가지가있을 것입니다 :

나는 컴팩트 한 표현처럼 원하는 10 년

'foobaz2205-11' 

몇 가지 간결한 방법이 있나요?

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

이상적인 스크립트를 깔끔하게 할 수있는 경우에 다시 'firstname2301-lastname9922'에 떨어질 것이다 '내가 좋아하는 임베디드 시퀀스를 처리하기위한 ... 그래서 조금 부드럽게,

보너스 포인트를 큰 펄 해커가 아니에요 이름의 순서를 식별합니다.

+2

이 질문은 미달합니다. 가능한 모든 입력을 처리하는 일련의 규칙을 생각해 내야합니다. 마지막 예를 들어, 묵시적인 단순화'foobar33-35-pqq'는 맥락에서 모호한 것으로 판명 될 수 있습니다. 숫자와 붕괴 시퀀스를 추출하는 기본 개념은 Perl의 정규 표현식을 보면 매우 간단하지만, 더 큰 문제는 실제로하고 싶은 것을 결정하는 것입니다. –

+0

고정되어 있다고 생각합니다. 'foobar33-35-pqq'에 모호성이 보이지 않습니다. 참고 차이점은 ** ** ** 인접한 숫자 자릿수입니다. 이름에 하나 이상의 자릿수가 있으면 보석금을냅니다. –

+0

당신이 원하는 것은 문자열을 배열 ('@list = split (","$ names)'또는 이와 비슷한 것)로 분할 한 다음 [가장 긴 공통 접두사]를 찾는 것입니다 (http://stackoverflow.com/questions/9114402/regexp-finding-longest-common-of-two-strings)을 사용하여 배열에있는 단어를 찾습니다. 가장 긴 공통 접미사를 찾는 보너스 포인트. 따라서 접두어, 가변 부분 및 접미사로 단어를 분리하십시오. 그러면 당신의 대답은 "$ prefix $ varFirst"입니다. "-". "$ varLast $ suffix". 그게 옳은 것 같니? –

답변

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