Glob eşleştirici uygulayın


15

Eşleştirilecek desen ve dize işlevini uygulayın, desen BÜTÜN dizesiyle eşleşirse true değerini, aksi takdirde false değerini döndürün.

Glob pattern sözdizimimiz:

  • ? herhangi bir karakterle eşleşir
  • + bir veya daha fazla karakterle eşleşir
  • * sıfır veya daha fazla karakterle eşleşir
  • \ kaçar

Kurallar:

  • Hiçbir eval, düzenli ifadeye dönüştürmek yok, sistem glob fonksiyonu çağırmak yok.
  • G / Ç gerekli değildir: sadece bir işlev yazabilirsiniz
  • En kısa kazançlar

Örnekler:

glob('abc', 'abc') => true
glob('abc', 'abcdef') => false IMPORTANT!
glob('a??', 'aww') => true
glob('a*b', 'ab') => true
glob('a*b', 'agwijgwbgioeb') => true
glob('a*?', 'a') => false
glob('?*', 'def') => true
glob('5+', '5ggggg') => true
glob('+', '') => false
glob('a\*b', 'a*b') => true

Başlamak için bir ipucu: http://en.wikipedia.org/wiki/Backtracking


1
Ek bir "kalıp eşleme" etiketi önerebilir miyim?
dmckee --- eski moderatör yavru kedi

1
Ne demek istediğini "standart işlev yok" ile açıklayabilir misin? Standart kitaplıktaki işlevleri çağıramayacağınızı mı? Bunun nasıl çalışması gerekiyor?
sepp2k

Kaçmak için bazı örnekler lütfen? ("\")
Eelvex

Yanıtlar:


4

Golfscript - 82 karakter

{1,\@n+:|;{:<;{:I)I|="\\+*?"[<]+?[{|=<={I))}*}I~{I\C}{}.{;}]=~}:C%}/{|>'*'-n=},}:g

Dizelerde yeni satır olmadığını varsayar. False için boş bir dizi ve true için boş olmayan bir dizi (true / false golfscript tanımıyla tutarlı) döndürür.

Bu, yinelenen olmayan bir çözümdür (ardışık *s dışında ), desen dizesindeki konumların bir listesini tutar ve iböylece pattern[0..i]eşleşir string[0..cur].

Bunun çok uzun süre koşma potansiyeli vardır. Bunu önlemek için .&sonradan ekleyebilirsiniz :C%.


5

Haskell, 141 karakter

c('\\':a:z)s=a&s>>=c z
c(a:z)s=a%s>>=c z
c[]s=[null s]
p&(a:z)|a==p=[z]
_&_=[]
'?'%(a:z)=[z]
'*'%a=a:'+'%a
'+'%(a:z)='*'%z
l%a=l&a
g=(or.).c

Tüm girişler için çalışır, hem desen hem de dizgilerle eşleşir. Desendeki ters eğik çizgiyi gerçek bir eşleşme olarak işler (davranış belirtilmedi.)

Bu, aşağıdaki test sürücüsü ile çalıştırılabilir:

main = do
    globtest "abc" "abc"    True
    globtest "abc" "abcdef" False
    globtest "a??" "aww"    True
    globtest "a*b" "ab"     True
    globtest "a*b" "agwijgwbgioeb" True
    globtest "a*?" "a"      False
    globtest "?*" "def"     True
    globtest "5+" "5ggggg"  True
    globtest "+" ""         False
    globtest "a\\*b" "a*b"  True
  where
    globtest p s e =
      if g p s == e
        then putStrLn "pass"
        else putStrLn$"fail: g " ++ show p ++ " " ++ show s ++ " /= " ++ show e

Güncelleme: Haskell'in problemi nasıl bu kadar kolay kodladığını iyi gösterdiğini düşündüğüm için bu özel cevap hakkında bir blog yazısı yazdım .


  • Düzenleme: (181 -> 174) değiştirildi dve moperatörlerle
  • Düzenleme: (174 -> 151) satır riçinec
  • Düzenleme: (151 -> 149) 'de gereksiz oluşturulan seçeneği kaldırıldı +durumda
  • Düzenleme: (149 -> 141) %tarafından işlenen gereksiz bir cümle kaldırıldı .&

2

PHP - 275 243 karakter

<?function g($P,$I){$o='array_shift';if(@$I[0]==="")return 0;for(;$P;$o($P)){$p=$P[0];if($p=='?'|$p=='+'&&@$N===$o($I))return 0;if($p=='+'|$p=='*'&&$I&&g($P,array_slice($I,1)))return 1;if(!strpos(" ?+*\\",$p)&&$p!==$o($I))return 0;}return!$I;}

Ungolfed:

<?php

function g($P,$I) {
        if ($I && $I[0] === "") return false;
        for(;$P;array_shift($P)) {
                $p = $P[0];
                if( $p == '?' || $p == '+') {
                        if (NULL === array_shift($I)) {
                                return false;
                        }
                }
                if( $p=='+' || $p=='*' ) {
                        if ($I && g($P, array_slice($I,1))) {
                                return true;
                        }
                }
                if (!strpos(" ?+*\\",$p) && $p !== array_shift($I)) {
                        return false;
                }
        }
        return !$I;
}

function my_glob($pattern,$subject) {
    return !!g(str_split($pattern),str_split($subject));
}

2

Aşırı Ayrıntılı Python ( 384 367 Özellikleri)

t=lambda a:a[1:] 
h=lambda a:a[0] 
n=lambda p,s:s and(h(p)==h(s)and m(t(p),t(s))) 
def m(p,s): 
 if not p: 
  return not s 
 else: 
  return { 
   '?':lambda p,s:s and m(t(p),t(s)), 
   '+':lambda p,s:s and(m(p,t(s))or m(t(p),t(s))), 
   '*':lambda p,s:m(t(p),s)or(s and m(p,t(s))), 
   '\\':lambda p,s:n(t(p),s), 
  }.get(h(p),n)(p,s) 
glob=lambda p,s:not not m(p,s)

En kısa değil, ama güzel ve işlevsel. Ortadaki sevkıyat dict şey muhtemelen yazım (h(p) == '?') and (? lambda body)şeyler üzerinde bir ayrım olarak yeniden yazılabilir . H operatörünün tanımlanması bana hiçbir faydası olmayan bazı karakterlere mal olur, ancak kafa için bir anahtar kelime olması güzel.

Zaman izin verirse daha sonra golfscripting bir çatlak istiyorum.

edit: user300'ün yakut cevabını okuduktan sonra '*' durumunda gereksiz üçüncü dal kaldırıldı


2

Daha Kısa Snappier Python 2.6 (272 karakter)

golfed:

n=lambda p,s:p[0]==s[0]and m(p[1:],s[1:]) 
def m(p,s): 
 q,r,t,u=p[0],p[1:],s[0],s[1:] 
 return any((q=='?'and(t and m(r,u)),q=='+'and(t and(m(p,u)or m(r,u))),q=='*'and(m(r,s)or(t and m(p,u))),q=='\\'and n(r,s),q==t==0))or n(p,s) 
glob=lambda*a:m(*[list(x)+[0]for x in a])

ungolfed:

TERMINATOR = 0 

def unpack(a): 
    return a[0], a[1:] 

def terminated_string(s): 
    return list(s) + [TERMINATOR] 

def match_literal(p, s): 
    p_head, p_tail = unpack(p) 
    s_head, s_tail = unpack(s) 
    return p_head == s_head and match(p_tail, s_tail) 

def match(p, s): 
    p_head, p_tail = unpack(p) 
    s_head, s_tail = unpack(s) 
    return any(( 
        p_head == '?' and (s_head and match(p_tail, s_tail)), 
        p_head == '+' and (s_head and(match(p, s_tail) or match(p_tail, s_tail))), 
        p_head == '*' and (match(p_tail, s) or (s_head and match(p, s_tail))), 
        p_head == '\\' and match_literal(p_tail, s), 
        p_head == s_head == TERMINATOR, 
    )) or match_literal(p, s) 

def glob(p, s): 
    return match(terminated_string(p), terminated_string(s))

sahip:

  • tembel olarak değerlendirilen mantıksal karışıklık!
  • C tarzı dizeleri!
  • sevimli çoklu karşılaştırma deyimi!
  • bol çirkin!

Boş bir dizeden kafa patlattığınızda bir tür sonlandırıcı değeri elde edebiliyorsanız, işlerin nasıl basitleştirildiğini göstermek için user300'ün cevabına teşekkür ederiz.

keşke m / argüman bildirimi sırasında baş / kuyruk açma inline yapılabilir. o zaman m bir lambda olabilir, tıpkı arkadaşları n ve glob gibi. python2 bunu yapamaz ve biraz okuduktan sonra python3 de yapamaz gibi görünür. vah.

test yapmak:

test_cases = { 
    ('abc', 'abc') : True, 
    ('abc', 'abcdef') : False, 
    ('a??', 'aww') : True, 
    ('a*b', 'ab') : True, 
    ('a*b', 'aqwghfkjdfgshkfsfddsobbob') : True, 
    ('a*?', 'a') : False, 
    ('?*', 'def') : True, 
    ('5+', '5ggggg') : True, 
    ('+', '') : False, 
}   
for (p, s) in test_cases: 
    computed_result = glob(p, s) 
    desired_result = test_cases[(p, s)] 
    print '%s %s' % (p, s) 
    print '\tPASS' if (computed_result == desired_result) else '\tFAIL' 

2

Yakut - 199 171

g=->p,s{x=(b=->a{a[1..-1]})[p];y=s[0];w=b[s];v=p[0];_=->p,s{p[0]==y&&g[x,w]}
v==??? g[x,y&&w||s]:v==?+? y&&g[?*+x,w]:v==?*?
y&&g[p,w]||g[x,s]:v==?\\? _[x,s]:v ? _[p,s]:!y}

Ungolfed:

def glob(pattern, subject)
        b=->a{a[1..-1]}
        _=->p,s{ p[0]==s[0] && glob(b[p],b[s]) }
        ({
                ??=>->p,s { glob(b[p], s[0] ? b[s] : s) },
                ?+=>->p,s { s[0] && glob(?*+b[p], b[s]) },
                ?*=>->p,s { s[0] && glob(p,b[s]) || glob(b[p],s) },
                ?\\=>->p,s{ _[b[p],s] },
                nil=>->p,s{ !subject[0] }
        }[pattern[0]] || _)[pattern, subject]
end

Testler:

p glob('abc', 'abc')
p glob('abc', 'abcdef')
p glob('a??', 'aww')
p glob('a*b', 'ab')
p glob('a*b', 'agwijgwbgioeb')
p glob('a*?', 'a')
p glob('?*', 'def')
p glob('5+', '5ggggg')
p glob('+', '')

Roobs'un cevabından ilham aldı


yakut hakkında hiçbir şey bilmiyorum, ama kodundan sınırların dışında indekslere erişim nil döner öğrendim. bu nedenle boş bir dizgenin patlatılması, bir dizgi sonlandırıcı sembolü olarak kullanılabilen bir sıfır değeri verir. C tarzı! şık! sanırım her giriş dizesi üzerinden geçirerek piton taklit olabilirlambda s : list(s)+[None]
roobs

Görünüşe göre, Ruby desen eşleştirme yapmıştır. Bu tür bir sorun için kesinlikle kullanışlıdır.
Jonathan M Davis

Aslında, ??gerçek karakter, =>Ruby Hashes'te anahtar / değer ayırıcılarıdır ve ->bir lambda başlatır :-) ( { ?? => ->{...} }anahtar ile bir karma "?"ve değer olarak bir lambdadır.) :-)
Arnaud Le Blanc

2

C işlevi - 178 gerekli karakter

GCC ile derlendiğinde bu hiçbir uyarı oluşturmaz.

#define g glob
int g(p,s)const char*p,*s;{return*p==42?g(p+1,s)||(*s&&g(p,
s+1)):*p==43?*s&&(g(p+1,++s)||g(p,s)):*p==63?*s&&g(p+1,s+1)
:*p==92?*++p&&*s++==*p++&&g(p,s):*s==*p++&&(!*s++||g(p,s));}
#undef g

İlk ve son satırlar karakter sayısına dahil edilmez. Bunlar yalnızca kolaylık olması açısından sağlanmıştır.

Üflemeli-up:

int glob(p,s)
const char *p, *s; /* K&R-style function declaration */
{
    return
        *p=='*'  ? glob(p+1,s) || (*s && glob(p,s+1)) :
        *p=='+'  ? *s && (glob(p+1,++s) || glob(p,s)) :
        *p=='?'  ? *s && glob(p+1,s+1)                :
        *p=='\\' ? *++p && *s++==*p++ && glob(p,s)    :
        *s==*p++ && (!*s++ || glob(p,s));
}

2

JavaScript - 259 karakter

Uygulamam çok özyinelemeli, bu nedenle çok uzun bir desen kullanılırsa yığın taşacak. Artı işaretini göz ardı ederek (optimize edebileceğim ancak basitlik için seçmedim), her jeton için bir seviye özyineleme kullanılır.

glob=function f(e,c){var b=e[0],d=e.slice(1),g=c.length;if(b=="+")return f("?*"+d,c);if(b=="?")b=g;else if(b=="*"){for(b=0;b<=g;++b)if(f(d,c.slice(b)))return 1;return 0}else{if(b=="\\"){b=e[1];d=e.slice(2)}b=b==c[0]}return b&&(!d.length&&!g||f(d,c.slice(1)))}

İşlev bazen bir boole yerine bir sayı döndürür. Bu bir sorunsa, olarak kullanabilirsiniz !!glob(pattern, str).


Yararlı bir kaynak olarak hizmet etmek için yönlendirilmemiş (yerine getirilmemiş):

function glob(pattern, str) {
    var head = pattern[0], tail = pattern.slice(1), strLen = str.length, matched;
    if(head == '+') {
        // The plus is really just syntactic sugar.
        return glob('?*' + tail, str);
    }
    if(head == '?') { // Match any single character
        matched = strLen;
    } else if(head == '*') { // Match zero or more characters.
        // N.B. I reuse the variable matched to save space.
        for(matched = 0; matched <= strLen; ++matched) {
            if(glob(tail, str.slice(matched))) {
                return 1;
            }
        }
        return 0;
    } else { // Match a literal character
        if(head == '\\') { // Handle escaping
            head = pattern[1];
            tail = pattern.slice(2);
        }
        matched = head == str[0];
    }
    return matched && ((!tail.length && !strLen) || glob(tail, str.slice(1)));
}

Dizi öğeleri için olduğu gibi bir dizenin karakterlerine endekslemenin daha eski (ECMAScript 3) dil standardının bir parçası olmadığını unutmayın, bu nedenle eski tarayıcılarda çalışmayabilir.


1

Python (454 karakter)

def glob(p,s):
  ps,pns=[0],[]
  for ch in s:
    for i in ps:
      if i<0:
        pns+=[i]
        if i>-len(p) and p[-i]==ch:pns+=[-i]
      elif i<len(p):
        pc=p[i]
        d={'?':[i+1],'+':[i,-i-1],'*':[i+1,-i-1]}
        if pc in d:pns+=d[pc]
        else:
          if pc=='\\':pc=p[i+1]
          if pc==ch:pns+=[i+1]
    ps,pns=pns,[]
  if (s or p in '*') and (len(p) in ps or -len(p)+1 in ps or -len(p) in ps): return True
  return False

1

D: 363 Karakterler

bool glob(S)(S s,S t){alias front f;alias popFront p;alias empty e;while(!e(s)&&!e(t)){switch(f(s)){case'+':if(e(t))return false;p(t);case'*':p(s);if(e(s))return true;if(f(s)!='+'&&f(s)!='*'){for(;!e(t);p(t)){if(f(s)==f(t)&&glob(s,t))return true;}}break;case'\\':p(s);if(e(s))return false;default:if(f(s)!=f(s))return false;case'?':p(s);p(t);}}return e(s)&&e(t);}

Daha okunaklı:

bool glob(S)(S s, S t)
{
    alias front f;
    alias popFront p;
    alias empty e;

    while(!e(s) && !e(t))
    {
        switch(f(s))
        {
            case '+':
                if(e(t))
                    return false;

                p(t);
            case '*':
                p(s);

                if(e(s))
                    return true;

                if(f(s) != '+' && f(s) != '*')
                {
                    for(; !e(t); p(t))
                    {
                        if(f(s) == f(t) && glob(s, t))
                            return true;
                    }
                }

                break;
            case '\\':
                p(s);

                if(e(s))
                    return false;
            default:
                if(f(s) != f(s))
                    return false;
            case '?':
                p(s);
                p(t);
        }
    }

    return e(s) && e(t);
}

1

golfscript

{{;;}2$+}:x;{x if}:a;{x\if}:o;{1$1$}:b;{(@(@={\m}a}:r;{b(63={\({\m}a}a{b(43={\({\b m{'+'\+m}o}a}a{b(42={b m{\({\'*'\+m}a}o}a{b(92={r}a{b 0=0=\0=0=*{r}o}o}o}o}o}:m;{[0]+\[0]+m}:glob;

yığın ve s'den iki bağımsız değişken tüketen ve tek bir boole dönüş değeri üreten işlevlerden oluşur. tembel ve tembel ya da operatörlerle uyumlu hale getirmek için biraz mucking var. Gerçekten bu yaklaşımın optimal, hatta doğru yönde olduğu her yerde olduğundan şüpheliyim.

Ayrıca , sadece bir sonraki dalın eşleşmediğini fark etmek için, bir karşılaştırmada '*'tüketmek, paterni patlatmak , '*'karşılaştırmayı tüketmek gibi birkaç aptal an da var . diğer daldan aşağı inmek için '*', ön taraftaki desene ihtiyacımız var , ancak patladığında orijinal kalıbı '*'tükettik ve tükettik '*', bu yüzden kendimize desen almak için parlak yeni bir dize yüklüyoruz sabiti '*'ve başa getirebilir o yerde. daha da çirkinleşir, çünkü bazı nedenlerden dolayı karakter eşleşmesinin ascii değerleriyle yapılması gerekir, ancak dizgeye geri dönmek için dizelere ihtiyaç vardır.

daha az golf sahası

{[0]+}:terminate_string;
{{;;}2$+if}:_and;
{{;;}2$+\if}:_or;
{1$1$}:branch;
{(@(@={\match}_and}:match_literal;
{0=0=\0=0=*}:match_terminator;
{(92={match_literal}_and}:match_escape;
{(63={\({\match}_and}_and}:match_wildcard;
{(43={\({\branch match{'+'\+match}_or}_and}_and}:match_wildcard_plus;
{(42={branch match{\({\'*'\+match}_and}_or}_and}:match_wildcard_star;
{branch match_wildcard{branch match_wildcard_plus{branch match_wildcard_star{branch match_escape{branch match_terminator{match_literal}_or}_or}_or}_or}_or}:match;
{terminate_string\terminate_string match}:glob;

testler

{2$2$glob = "test passed: " "test FAILED: " if print \ print ' ; ' print print "\n" print}:test_case;

'abc' 'abc' 1 test_case
'abc' 'abcdef' 0 test_case
'a??' 'aww' 1 test_case
'a*b' 'ab' 1 test_case
'a*b' 'agwijgwbgioeb' 1 test_case
'a*?' 'a' 0 test_case
'?*' 'def' 1 test_case
'5+' '5ggggg' 1 test_case
'+' '' 0 test_case

1

C # (251 karakter)

static bool g(string p,string i){try{char c;System.Func<string,string>s=t=>t.Remove(0,1);return p==i||((c=p[0])==92?p[1]==i[0]&g(s(s(p)),s(i)):c==42?g(s(p),i)||g(p,s(i)):c==43?g(s(p),s(i))|g(p,s(i)):g(s(p),s(i))&(c==i[0]|c==63));}catch{return false;}}

Biraz daha okunabilir:

static bool g(string p /* pattern */, string i /* input string */)
{
    // Instead of checking whether we’ve reached the end of the string, just
    // catch the out-of-range exception thrown by the string indexing operator
    try
    {
        char c;

        // .Remove(0,1) is shorter than .Substring(1)...
        System.Func<string, string> s = t => t.Remove(0, 1);

        // Note that every glob matches itself!† This saves us having to write
        // “(p=="" & i=="")” which would be much longer — very convenient!
        return p == i || (

            // backslash escapes
            (c = p[0]) == 92 ? p[1] == i[0] & g(s(s(p)), s(i)) :

            // '*' — need “||” so that s(i) doesn’t throw if the first part is true
            c == 42 ? g(s(p), i) || g(p, s(i)) :

            // '+'
            c == 43 ? g(s(p), s(i)) | g(p, s(i)) :

            // '?' or any other character
            g(s(p), s(i)) & (c == i[0] | c == 63)
        );
    }

    // If we ever access beyond the end of the string, we know the glob doesn’t match
    catch { return false; }
}

Biliyorum, biliyorum ... ters eğik çizgi içeren küreler hariç. Bu gerçekten talihsiz. Aksi takdirde gerçekten akıllı olurdu. :(

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.