ติดตั้ง glob Matcher


15

ใช้ฟังก์ชั่นของรูปแบบและสตริงที่จะจับคู่คืนค่าจริงถ้ารูปแบบตรงกับสตริง WHOLE มิฉะนั้นเป็นเท็จ

ไวยากรณ์รูปแบบ glob ของเราคือ:

  • ? ตรงกับตัวละครตัวใดตัวหนึ่ง
  • + ตรงกับตัวละครหนึ่งตัวหรือมากกว่า
  • * ตรงกับอักขระศูนย์หรือมากกว่า
  • \ หนี

กฎ:

  • ไม่มี eval ไม่แปลงเป็นนิพจน์ทั่วไปไม่เรียกฟังก์ชัน glob ระบบ
  • ไม่จำเป็นต้องใช้ I / O คุณสามารถเขียนฟังก์ชั่นได้
  • ชนะสั้นที่สุด

ตัวอย่าง:

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

นี่คือเคล็ดลับในการเริ่มต้น: http://en.wikipedia.org/wiki/Backtracking


1
ฉันขอแนะนำแท็ก "การจับคู่รูปแบบ" เพิ่มเติมหรือไม่
dmckee --- ผู้ดูแลอดีตลูกแมว

1
คุณสามารถอธิบายสิ่งที่คุณหมายถึงโดย "ไม่มีฟังก์ชั่นมาตรฐาน"? คุณไม่สามารถเรียกฟังก์ชันจากไลบรารีมาตรฐานได้หรือไม่ มันควรจะทำงานอย่างไร
sepp2k

โปรดยกตัวอย่างเกี่ยวกับการหลบหนี ("\")
Eelvex

คำตอบ:


4

Golfscript - 82 ตัวอักษร

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

สมมติว่าไม่มีการขึ้นบรรทัดใหม่ในสตริง ส่งคืนอาร์เรย์ที่ว่างเปล่าสำหรับเท็จและอาร์เรย์ที่ไม่ว่างเปล่าสำหรับจริง (สอดคล้องกับคำนิยาม golfscript ของจริง / เท็จ)

นี่เป็นวิธีแก้ปัญหาแบบไม่เรียกซ้ำ (ยกเว้น*s ต่อเนื่อง) ซึ่งเก็บรายการของตำแหน่งในสตริงรูปแบบiเช่นpattern[0..i]ตรงกับstring[0..cur]การแข่งขัน

สิ่งนี้มีศักยภาพในการทำงานเป็นเวลานานมาก คุณสามารถเพิ่ม.&หลังจาก:C%เพื่อป้องกันสิ่งนี้


5

Haskell, 141 ตัวอักษร

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

ใช้งานได้กับอินพุตทั้งหมดทั้งรูปแบบและสตริงเพื่อให้ตรงกับ จัดการเครื่องหมายแบ็กสแลชต่อท้ายในรูปแบบเป็นการจับคู่ตามตัวอักษร (พฤติกรรมไม่ได้ระบุ)

สิ่งนี้สามารถรันด้วยไดร์เวอร์ทดสอบต่อไปนี้:

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

อัปเดต:ฉันเขียนโพสต์บล็อกเกี่ยวกับคำตอบเฉพาะนี้เนื่องจากฉันคิดว่ามันแสดงให้เห็นได้ดีว่า Haskell เข้ารหัสปัญหาได้อย่างไร


  • แก้ไข: (181 -> 174) ถูกแทนที่ dและmกับผู้ประกอบการ
  • แก้ไข: (174 -> 151) ถูกแทรก rแทรกเข้าไปc
  • แก้ไข: (151 -> 149) ลบตัวเลือกที่สร้างขึ้นโดยไม่จำเป็นใน +กรณี
  • แก้ไข: (149 -> 141) ลบข้อที่ไม่จำเป็นสำหรับ%ซึ่งได้รับการจัดการโดย&

2

PHP - 275 243 ตัวอักษร

<?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

Overly Verbose Python ( 384 367 ตัวอักษร)

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)

มันไม่สั้น แต่ก็ดีและใช้งานได้ สิ่งที่เขียนตามคำบอกกลางอาจสันนิษฐานได้ว่าเป็นความแตกแยก(h(p) == '?') and (? lambda body)สิ่งที่พิมพ์ การกำหนดตัวดำเนินการ h ทำให้ฉันต้องเสียค่าใช้จ่ายบางตัวอักษรโดยไม่มีประโยชน์ แต่ก็ดีที่มีคำสำคัญ

ฉันต้องการมีรอยแตกที่สนามกอล์ฟในภายหลังถ้าเวลาอนุญาต

แก้ไข: ลบสาขาที่สามที่ไม่จำเป็นในกรณี '*' หลังจากอ่านคำตอบทับทิมของ user300


2

Shorter Snappier Python 2.6 (272 ตัวอักษร)

แข็งแรงเล่นกอล์ฟ:

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))

เนื้อเรื่อง:

  • ระเบียบตรรกะอย่างเกียจคร้าน!
  • สตริงสไตล์ C!
  • เปรียบเทียบสำนวนที่น่ารักหลาย!
  • น่าเกลียดมากมาย!

ให้เครดิตกับคำตอบของ user300 เพื่อแสดงให้เห็นว่าสิ่งต่าง ๆ ง่ายขึ้นอย่างไรถ้าคุณสามารถรับค่าเทอร์มิเนเตอร์บางชนิดเมื่อโผล่หัวจากสตริงว่าง

ฉันหวังว่าหัว / หางเปิดออกสามารถดำเนินการแบบอินไลน์ในระหว่างการประกาศข้อโต้แย้งของ m ถ้าเช่นนั้นเอ็มอาจเป็นแลมบ์ดาเหมือนเพื่อนและกลม python2 ไม่สามารถทำได้และหลังจากอ่านหนังสือไปเล็กน้อยดูเหมือนว่า python3 จะไม่สามารถทำได้เช่นกัน ความฉิบหาย

ในการทดสอบ:

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

ทับทิม - 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

แบบทดสอบ:

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('+', '')

แรงบันดาลใจจากคำตอบของร็อบ


ฉันไม่รู้อะไรเกี่ยวกับทับทิม แต่จากรหัสของคุณฉันได้เรียนรู้ว่าการเข้าถึงดัชนีที่ไม่อยู่ในขอบเขตจะส่งกลับศูนย์ ดังนั้นการ popping สตริงว่างจะให้ค่าเป็นศูนย์ซึ่งสามารถใช้เป็นสัญลักษณ์ของ terminator ของสตริงได้ C-รูปแบบ! ดี! ฉันเดาว่ามันอาจจะเลียนแบบเป็นไพ ธ อนโดยผ่านสตริงอินพุตแต่ละอันผ่านlambda s : list(s)+[None]
roobs

จากรูปลักษณ์ของมันทับทิมได้สร้างการจับคู่รูปแบบ แน่นอนว่ามีประโยชน์สำหรับปัญหาแบบนี้
Jonathan M Davis

จริงๆแล้ว??คือตัวอักษรที่=>เป็นตัวคั่นคีย์ / ค่าใน Ruby Hashes และ->เริ่มแลมบ์ดา :-) ( { ?? => ->{...} }เป็นแฮชที่มีคีย์"?"และแลมบ์ดาเป็นค่า) แต่ใช่วิธีที่ใช้ร่วมกันดูเหมือนว่าการจับคู่รูปแบบบนตัวอักษรเดี่ยว :-)
Arnaud Le Blanc

2

ฟังก์ชั่น C - 178 ตัวละครที่จำเป็น

คอมไพล์ด้วย GCC สิ่งนี้จะไม่มีการเตือนใด ๆ

#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

บรรทัดแรกและบรรทัดสุดท้ายไม่รวมอยู่ในจำนวนอักขระ พวกเขามีไว้เพื่อความสะดวกเท่านั้น

พัดขึ้นมา:

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 ตัวอักษร

การใช้งานของฉันซ้ำมากดังนั้นกองซ้อนจะล้นหากใช้รูปแบบที่ยาวมาก ละเว้นเครื่องหมายบวก (ซึ่งฉันสามารถปรับให้เหมาะสม แต่เลือกที่จะไม่ทำเพื่อความง่าย) จะใช้การเรียกซ้ำหนึ่งระดับสำหรับแต่ละโทเค็น

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)))}

ฟังก์ชั่นบางครั้งส่งกลับตัวเลขแทนบูลีน !!glob(pattern, str)ถ้าเป็นปัญหาคุณสามารถใช้มันเป็น


Ungolfed (ไม่ระบุชื่อ) เพื่อใช้เป็นทรัพยากรที่มีประโยชน์:

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)));
}

โปรดทราบว่าการจัดทำดัชนีเป็นอักขระของสตริงสำหรับองค์ประกอบอาร์เรย์ไม่ได้เป็นส่วนหนึ่งของมาตรฐานภาษาเก่า (ECMAScript 3) ดังนั้นจึงอาจไม่ทำงานในเบราว์เซอร์รุ่นเก่า


1

Python (454 ตัวอักษร)

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 ตัวอักษร

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);}

ชัดเจนยิ่งขึ้น:

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;

มันสร้างขึ้นจากฟังก์ชั่นที่ใช้สองอาร์กิวเมนต์จาก stack, s และ p และสร้างค่าบูลีนคืนเดียว มีการล้อเล่นเพื่อให้เข้ากันได้กับคนขี้เกียจและขี้เกียจหรือผู้ปฏิบัติงาน ฉันสงสัยจริงๆว่าวิธีการนี้อยู่ในตำแหน่งที่เหมาะสมหรือแม้กระทั่งในทิศทางที่ถูกต้อง

นอกจากนี้ยังมีช่วงเวลาที่สนุกสนานอย่างโง่เง่าไม่กี่ครั้งเช่นการ'*'ปิดแบบแผนการใช้เวลา'*'ในการเปรียบเทียบเพียงเพื่อให้ตระหนักว่าสาขาที่ตามมาไม่ตรงกัน เพื่อที่จะลงไปที่สาขาอื่นเราต้องการรูปแบบที่มี'*'ด้านหน้า แต่เราได้ใช้รูปแบบดั้งเดิมนั้นเมื่อเราตอก'*'และเราก็ใช้'*'มันดังนั้นเราจะได้รูปแบบใหม่อีกครั้งเราโหลดสตริงใหม่ที่เป็นประกาย คงที่'*'และเสริมมันเข้าที่ มันจะดูน่าเกลียดยิ่งกว่าเดิมเพราะด้วยเหตุผลบางอย่างการจับคู่อักขระต้องทำด้วยค่า ascii แต่การย้อนกลับไปยังสตริงต้องการสตริง

golfscript golfed น้อย

{[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;

การทดสอบ

{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 ตัวอักษร)

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;}}

อ่านง่ายขึ้นเล็กน้อย:

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; }
}

ฉันรู้ฉันรู้ ... ยกเว้น globs ที่มีแบ็กสแลช ซึ่งโชคร้ายจริงๆ มันคงเป็นสิ่งที่ฉลาดจริงๆ :(

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.