Triển khai toàn cầu Matcher


15

Thực hiện chức năng của mẫu và chuỗi được khớp, trả về true nếu mẫu phù hợp với chuỗi WHOLE, nếu không thì sai.

Cú pháp mẫu toàn cầu của chúng tôi là:

  • ? phù hợp với bất kỳ một nhân vật
  • + phù hợp với một hoặc nhiều nhân vật
  • * khớp với 0 hoặc nhiều ký tự
  • \ trốn thoát

Quy tắc:

  • Không eval, không chuyển đổi thành biểu thức chính quy, không gọi hàm toàn cầu hệ thống.
  • I / O không bắt buộc: bạn chỉ có thể viết một hàm
  • Chiến thắng ngắn nhất

Ví dụ:

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

Đây là một mẹo để bắt đầu: http://en.wikipedia.org/wiki/Backtracking


1
Tôi có thể đề xuất một thẻ bổ sung "khớp mẫu" không?
dmckee

1
Bạn có thể làm rõ những gì bạn có nghĩa là "không có chức năng tiêu chuẩn"? Rằng bạn không thể gọi các chức năng từ thư viện tiêu chuẩn? Làm thế nào là phải làm việc?
sepp2k

Một số ví dụ về việc trốn thoát xin vui lòng? ("\")
Mười

Câu trả lời:


4

Golfscript - 82 ký tự

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

Giả sử rằng không có dòng mới trong chuỗi. Trả về một mảng trống cho false và một mảng không trống cho true (phù hợp với định nghĩa golfscript là true / false).

Đây là một giải pháp không đệ quy (ngoại trừ các *s liên tiếp ), duy trì một danh sách các vị trí trong chuỗi mẫu isao cho pattern[0..i]khớp string[0..cur].

Điều này có tiềm năng để chạy trong một thời gian rất dài. Bạn có thể thêm .&sau :C%để ngăn chặn điều này.


5

Haskell, 141 ký tự

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

Hoạt động cho tất cả đầu vào, cả mẫu và chuỗi để khớp với. Xử lý dấu gạch chéo ngược trong mẫu dưới dạng khớp theo nghĩa đen (hành vi không được chỉ định.)

Điều này có thể được chạy với trình điều khiển thử nghiệm sau:

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

Cập nhật: Tôi đã viết một bài đăng trên blog về câu trả lời cụ thể này, vì tôi nghĩ rằng nó cho thấy rõ Haskell dễ dàng mã hóa vấn đề như thế nào.


  • Chỉnh sửa: (181 -> 174) được thay thế dmbằng toán tử
  • Chỉnh sửa: (174 -> 151) được rnhập vàoc
  • Chỉnh sửa: (151 -> 149) đã xóa tùy chọn được tạo không cần thiết trong +trường hợp
  • Chỉnh sửa: (149 -> 141) đã xóa một mệnh đề không cần thiết cho %, được xử lý bởi&

2

PHP - 275 243 ký tự

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

Ung dung:

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

Python quá dài ( 384 367 ký tự)

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)

Nó không phải là ngắn nhất, nhưng nó tốt đẹp và chức năng. Điều sai khiến công văn ở giữa có lẽ có thể được viết lại như một sự phân biệt đối với (h(p) == '?') and (? lambda body)những thứ loại. Xác định rằng toán tử h làm tôi mất một số ký tự không có lợi, nhưng thật tuyệt khi có một từ khóa cho đầu.

Tôi muốn có một vết nứt khi chơi golf sau này nếu thời gian cho phép.

chỉnh sửa: loại bỏ nhánh thứ ba không cần thiết trong trường hợp '*' sau khi đọc câu trả lời ruby ​​của user300


2

Snappier Python 2.6 ngắn hơn (272 ký tự)

đánh gôn

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

vô dụng:

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ó tính năng:

  • đánh giá logic lộn xộn!
  • C kiểu dây!
  • dễ thương nhiều thành ngữ so sánh!
  • nhiều xấu xí!

tín dụng cho câu trả lời của user300 để minh họa cách mọi thứ được đơn giản hóa nếu bạn có thể nhận được một số loại giá trị terminator khi bật đầu từ một chuỗi trống.

tôi muốn giải nén đầu / đuôi có thể được thực hiện nội tuyến trong quá trình khai báo các đối số của m. sau đó m có thể là một lambda, giống như bạn bè của nó và toàn cầu. python2 không thể làm điều đó, và sau khi đọc một chút, có vẻ như python3 cũng không thể. Khốn nạn.

thử nghiệm:

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

Hồng ngọc - 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}

Ung dung:

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

Các xét nghiệm:

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

Lấy cảm hứng từ câu trả lời của roobs


Tôi không biết gì về ruby, nhưng từ mã của bạn, tôi đã học được rằng việc truy cập vào các chỉ số giới hạn sẽ trả về con số không. do đó, xuất hiện một chuỗi rỗng mang lại một giá trị không có thể được sử dụng làm biểu tượng kết thúc chuỗi. Kiểu C! tiện lợi tôi đoán nó có thể được bắt chước trong python bằng cách chuyển từng chuỗi đầu vào qualambda s : list(s)+[None]
roobs

Từ vẻ ngoài của nó, Ruby đã được xây dựng phù hợp với mô hình. Điều đó chắc chắn có ích cho loại vấn đề này.
Jonathan M Davis

Trên thực tế, các ??ký tự theo nghĩa đen, =>là các dấu tách khóa / giá trị trong Ruby Hashes và ->bắt đầu một lambda :-) ( { ?? => ->{...} }là một hàm băm với khóa "?"và lambda là giá trị.) Nhưng vâng, cách nó được sử dụng cùng nhau trông giống như khớp mẫu :-)
Arnaud Le Blanc

2

Hàm C - 178 ký tự cần thiết

Được biên dịch với GCC, điều này không tạo ra cảnh báo.

#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

Các dòng đầu tiên và cuối cùng không được bao gồm trong số lượng nhân vật. Chúng chỉ được cung cấp để thuận tiện.

Thổi hồn:

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 ký tự

Việc triển khai của tôi rất đệ quy, vì vậy ngăn xếp sẽ tràn nếu sử dụng một mẫu cực kỳ dài. Bỏ qua dấu cộng (mà tôi có thể đã tối ưu hóa nhưng chọn không đơn giản), một mức đệ quy được sử dụng cho mỗi mã thông báo.

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

Hàm đôi khi trả về một số thay vì boolean. Nếu đó là một vấn đề, bạn có thể sử dụng nó như !!glob(pattern, str).


Ungolfed (chưa hoàn thành, thay vào đó) để phục vụ như một tài nguyên hữu ích:

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

Lưu ý rằng việc lập chỉ mục thành các ký tự của chuỗi như đối với các phần tử mảng không phải là một phần của tiêu chuẩn ngôn ngữ cũ (ECMAScript 3), do đó, nó có thể không hoạt động trong các trình duyệt cũ hơn.


1

Con trăn (454 ký tự)

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 Nhân vậ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);}

Dễ đọc hơn:

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

sân golf

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

nó được xây dựng từ các hàm tiêu thụ hai đối số từ ngăn xếp, s và p và tạo ra một giá trị trả về boolean duy nhất. có một chút mucking xung quanh để làm cho nó tương thích với người lười biếng và lười biếng hoặc người vận hành. tôi thực sự nghi ngờ phương pháp này là bất cứ nơi nào gần tối ưu, hoặc thậm chí đi đúng hướng.

cũng có một vài khoảnh khắc giải trí ngu ngốc, chẳng hạn như bật ra một '*'mô hình, sử dụng '*'một phép so sánh, chỉ để nhận ra rằng nhánh tiếp theo không khớp. để đi xuống nhánh khác, chúng ta cần mẫu có '*'ở mặt trước, nhưng chúng ta đã sử dụng mẫu ban đầu đó khi chúng ta xuất hiện '*'và chúng ta đã tiêu thụ '*', vì vậy để có được mẫu đó một lần nữa, chúng ta tải một chuỗi mới sáng bóng không đổi '*', và chuẩn bị nó tại chỗ. nó thậm chí còn xấu hơn bởi vì một số lý do, việc khớp ký tự cần được thực hiện với các giá trị ascii, nhưng việc quay lại chuỗi cần chuỗi.

ít chơi golf

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

kiểm tra

{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 ký tự)

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

Hơi dễ đọc hơn:

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

Tôi biết, tôi biết ... ngoại trừ những đống chứa dấu chéo ngược. Điều đó thực sự đáng tiếc. Nó sẽ thực sự thông minh khác. :(

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.