Từ viết tắt đệ quy


31

Mục tiêu

Từ Wikipedia :

Từ viết tắt đệ quy là từ viết tắt chỉ chính nó trong biểu thức mà nó đứng.

Mục tiêu của bạn là kiểm tra xem một chuỗi có phải là từ viết tắt đệ quy hay không.

  • Từ viết tắt là từ đầu tiên
  • Các từ không phân biệt chữ hoa chữ thường, phân tách bằng một khoảng trắng.
  • Chuỗi đã cho không chứa bất kỳ dấu chấm câu cũng như dấu nháy đơn.
  • Chỉ chữ cái đầu tiên của mỗi từ có thể là một phần của từ viết tắt.

Bạn cũng phải cung cấp cho các từ chức năng . Để đơn giản, mỗi từ có thể được coi là một từ chức năng.

Thí dụ

f("RPM Package Manager")         =>     { true, [] }
f("Wine is not an emulator")     =>     { true, ["an"] }
f("GNU is not Unix")             =>     { true, ["is"] }
f("Golf is not an acronym")      =>     { false }  
f("X is a valid acronym")        =>     { true, ["is","a","valid","acronym"] }  

Bạn có thể cung cấp một chương trình đầy đủ hoặc một chức năng.
Chuỗi đầu vào có thể được lấy từ STDIN hoặc làm đối số hàm.
Kết quả đầu ra có thể đúng / sai, 0/1, có / không ...
Danh sách từ chức năng (bất kỳ định dạng danh sách nào là hợp lệ) phải được đưa ra nếu và chỉ khi đây là từ viết tắt đệ quy (ngay cả khi danh sách trống) . Bạn không phải bảo toàn viết hoa của các từ chức năng.

Tiêu chí chiến thắng

Đây là một , mã ngắn nhất thắng.


4
Chúng ta có phải bảo toàn viết hoa của các từ chức năng không?
thuật toán

1
Có thể chấp nhận có một danh sách các chuỗi đi kèm với giá trị Sai hay không?
ngầmmonorail

1
Vì danh sách từ tự mã hóa giá trị boolean bằng sự hiện diện của nó, chúng ta có thể bỏ qua boolean không?
John Dvorak

5
Hurd là viết tắt của Hird of Unix-Thay thế Daemon. Hird là viết tắt của Hurd of Interfaces Đại diện cho Độ sâu. Tại sao các ví dụ ở đây không hiểu điều đó và yêu cầu những từ viết tắt không đệ quy?
Konrad Borowski

3
@xfix, wikipedia nói rằng đó là những từ viết tắt đệ quy lẫn nhau .
Michael M.

Câu trả lời:


7

GolfScript, 51 50 ký tự

{32|}%" "/(1>\{.1<2$1<={;1>}{\}if}/{]!}{]`1" "@}if

Nó có thể có thể được chơi golf hơn nữa. Đưa đầu vào vào STDIN. Boolean là 0/1.

Kiểm tra trực tuyến


Giải trình:

{32|}%      # change everything to lower-case
" "/        # splits the string by spaces
(1>         # takes the first word out and removes the first letter
\           # moves the list of remaining words in front of the acronym word
{           # for every word:
  .1<2$1<=    # compares the first letter of the word with
              # the next unmatched letter of the acronym
  {;1>}       # if they are the same, discard the word and the now-matched letter
  {\}         # otherwise store the word in the stack
  if          # NB. if all letters have been matched, the comparison comes out as false
}/
{]!}        # if there are still unmatched letters, return 0 (`!` non-empty list)
{]`1" "@}   # otherwise, return 1, and display the list of function words
if

22

Regex, hương vị .NET, 62 byte

(?i)(?<=^\w(?<c>\w)*)( \k<c>(?<-c>)\w+| (?<w>\w+))*$(?(c)(?!))

Bạn có thể kiểm tra nó ở đây . Nếu đầu vào là từ viết tắt đệ quy, điều này sẽ mang lại kết quả khớp và nhóm bắt giữ wsẽ chứa tất cả các từ chức năng. Nếu không, thì sẽ không có trận đấu.

Điều này không bảo toàn viết hoa của các từ chức năng (nhưng khớp với trường hợp không nhạy cảm).

Thật không may, người kiểm tra không hiển thị toàn bộ ngăn xếp của một nhóm bắt giữ có tên, nhưng nếu bạn đã sử dụng nó ở bất cứ đâu trong .NET, thì w nhóm sẽ chứa tất cả các từ chức năng theo thứ tự.

Đây là đoạn trích C # để chứng minh rằng:

var pattern = @"(?i)(?<=^\w(?<c>\w)*)( \k<c>(?<-c>)\w+| (?<w>\w+))*$(?(c)(?!))";
var input = new string[] {
    "RPM Package Manager",
    "Wine is not an emulator",
    "GNU is not Unix",
    "Golf is not an acronym",
    "X is a valid acronym"
};

var r = new Regex(pattern);
foreach (var str in input)
{
    var m = r.Match(str);
    Console.WriteLine(m.Success);
    for (int i = 0; i < m.Groups["w"].Captures.Count; ++i)
        Console.WriteLine(m.Groups["w"].Captures[i].Value);
}

Đây là một lời giải thích nhanh chóng. Tôi đang sử dụng các nhóm cân bằng của .NET để xây dựng một chồng các chữ cái viết tắt trong nhóm được đặt tên c, với đoạn mã này

^\w(?<c>\w)*

Bí quyết là tôi cần chữ cái thứ hai ở trên cùng của ngăn xếp và chữ cái cuối cùng ở dưới cùng. Vì vậy, tôi đặt tất cả những điều này trong một cái nhìn phù hợp với vị trí sau từ viết tắt. Điều này giúp, bởi vì .NET khớp với các giao diện nhìn từ phải sang trái, vì vậy nó gặp chữ cái cuối cùng trước.

Khi tôi có được ngăn xếp đó, tôi khớp phần còn lại của chuỗi từ với từ. Từ bắt đầu bằng chữ cái trên đầu từ viết tắt. Trong trường hợp đó, tôi bật lá thư đó từ ngăn xếp:

 \k<c>(?<-c>)\w+

Mặt khác, dù sao tôi cũng ghép từ đó và đẩy lên wngăn xếp mà sau đó sẽ chứa tất cả các từ chức năng:

 (?<w>\w+)

Cuối cùng, tôi đảm bảo rằng tôi đã đến cuối chuỗi $và cũng đảm bảo rằng tôi đã sử dụng hết tất cả các chữ cái từ viết tắt, bằng cách kiểm tra xem ngăn xếp có trống không:

(?(c)(?!))

Kiểm tra nó trên ideone.


1
Biểu thức chính quy tuyệt vời, nhưng câu hỏi nêu rõ "Bạn có thể cung cấp một chương trình đầy đủ hoặc một chức năng ".
Bàn chải đánh răng

4
@toothbrush Nếu OP quyết định loại bỏ câu trả lời của tôi dựa trên điều đó, thì hãy là như vậy. Nhưng tôi nghĩ rằng tôi có thể đưa ra quan điểm rằng đây là một chương trình đầy đủ trong ngôn ngữ là hương vị biểu thức chính quy của .NET (không phải là ngôn ngữ hoàn chỉnh Turing và một ngôn ngữ hơi khó sử dụng, nhưng vẫn là ngôn ngữ). Trong mọi trường hợp, tôi thích thực tế là tôi đã giải quyết nó bằng cách tiếp cận regex thuần túy và tôi muốn có câu trả lời không đủ tiêu chuẩn hơn là phá hủy "sự thanh lịch" đó (nếu bạn muốn) bằng cách biến nó thành "chỉ là một C # -answer sử dụng regex ".
Martin Ender

Điều đó tốt với tôi. Tôi chỉ muốn chỉ ra trong trường hợp bạn bỏ lỡ nó.
Bàn chải đánh răng

1
Tôi thích nó. Regexes có thể không phải là ngôn ngữ lập trình hoàn chỉnh Turing, nhưng tôi nghĩ điều này nên được tính.
Paul Draper

@PaulDraper Trên thực tế, tôi thậm chí sẽ không đặt cược vào hương vị regex của .NET không hoàn thành Turing ... các nhóm cân bằng và các giao diện phù hợp từ phải sang trái rất mạnh mẽ. Và PCRE chẳng hạn được biết là Turing hoàn chỉnh (cái đó có đệ quy, tôi không chắc các ngăn xếp trong .NET là đủ để mô phỏng phép lặp tùy ý).
Martin Ender

11

Python (158, không có regex)

Không phải là tôi không thích regexes. Đó là tôi không biết họ.

def f(x):
 s=x.lower().split();w=list(s[0][1:]);s=s[1:];o=[]
 if not w:return 1,s
 [w.pop(0)if i[0]==w[0]else o.append(i)for i in s]
 return(0,)if w else(1,o)

Ồ, tôi cũng đã có một phiên bản vô văn hóa:

def acronym(string):
    scentence = string.lower().split()
    word = scentence[0][1:]
    scentence = scentence[1:]
    over = []
    if not word: return 1, scentence
    for item in scentence:
        if item[0] == word[0]:
            word = word[1:]
        else:
            over.append(item)
    if word:
        return 0,
    return 1,over

5

Python 2.7 - 131 126 bytes

def f(s):
 s=s.lower().split();a,f=list(s[0]),[]
 for w in s:f+=0*a.pop(0)if a and w[0]==a[0]else[w]
 return(0,)if a else(1,f)

Makes a list of letters in the first word of the acronym. Then, for each word in the full string, get rid of the first element of that list we made if it is the same as the first letter of that word. Otherwise, add that word to the list of function words. To output, return not a (In python, any list other than the empty list is True-y, and the list is empty if it's a recursive acronym) and the list if not a.

Thanks to @ace for helping me fix an error/save some bytes.


On Python 2.7.3, I get SyntaxError: invalid syntax at the end of the return line.
pastebin.com slash 0mr8spkT

@ace Huh, I could have sworn it worked when I tested it. I must have changed something and forgot to test again. I'll work on a fix!
undergroundmonorail

You can use for w in s:f+=0*a.pop(0)if a and w[0]==a[0]else[w] which is shorter and doesn't rely on tabs. As for the return statement, I found 0if a else(1,f) which is shorter than your original.
pastebin.com slash 0mr8spkT

Oh and if you use semicolons to put the first two statements in the same line you save one byte of indentation.
pastebin.com slash 0mr8spkT

1
I figured out a way to fix the error, but when I came back here to post it you had golfed it down more in the comments :P
undergroundmonorail

3

Python - 154 characters

First ever code golf attempt. I'm thinking python isn't the best language for it, given all the long keywords. Also, I don't think this function is foolproof. It works for the OP's input, but I'm sure I could think up exceptions.

def f(s):
    w=s.lower().split();r=list(w[0]);return(True,[x for x in w if x[0]not in r])if len(r)==1 or[x for x in[y[0]for y in w]if x in r]==r else False

I count 156 characters (the newline and the tab character both count), but you can get it down to 154 legitimately by removing those two characters since neither are actually required. Welcome to PPCG, btw. :)
undergroundmonorail

3

ECMAScript 6 (105 bytes):

f=s=>(r=(a=s.toUpperCase(i=1).split(' ')).map((w,c)=>c?a[0][i]==w[0]?(i++,''):w:''),a[0].length==i?1+r:0)

Enter the function in Firefox's browser console, and then just call the function, like this:

f('ABC Black Cats')     // 1,,
f('ABC is Black Cats')  // 1,IS,,
f('ABC Clapping Cats')  // 0

Doesn't quite comply with the rules: The function words list ... must be given if and only if this is a recursive acronym. This will alert them regardless.
MT0

@MT0 OK. I didn't notice that requirement. I'll see if I can rewrite it.
Toothbrush

@MT0 I've updated the code now.
Toothbrush

2

Haskell - 287 bytes

Not the shortest entry (hey this is Haskell, what did you expect?), but still a lot a fun to write.

import Data.Char
import Data.List
f""w=map((,)False)w
f _[]=[]
f(a:as)(cs@(c:_):w) 
 |toLower a==toLower c=(True,cs):f as w
 |True=(False,cs):f(a:as)w
g s=if(length$filter(fst)d)==length v
  then Just$map(snd)$snd$partition(fst)d 
  else Nothing
 where 
  w=words s
  v=head w
  d=f v w

Tested with

map (g) ["RPM Package Manager","Wine is not an emulator","GNU is not Unix","Golf is not an acronym","X is a valid acronym"]

Expected output

[Just [],Just ["an"],Just ["is"],Nothing,Just ["is","a","valid","acronym"]]

Ungolfed

import Data.Char
import Data.List

f :: String -> [String] -> [(Bool, String)]
f "" w = map ((,) False) w
f _ [] = []
f (a:as) ((c:cs):w) | toLower a == toLower c = (True, c:cs) : f as w
                    | otherwise = (False, c:cs) : f (a:as) w

g :: String -> Maybe [String]
g s = if (length $ filter (fst) d) == (length v)
          then Just $ map (snd) $ snd $ partition (fst) d 
          else Nothing
  where w = words s
        v = head w
        d = f v w

2

JavaScript (ECMAScript 6) - 97 Characters

f=x=>(r=(a=x.toLowerCase(i=0).split(' ')).filter(y=>y[0]!=a[0][i]||i-i++),i==a[0].length?[1,r]:0)

Tests:

f("RPM Package Manager")
[1, []]

f("GNU is not Unix")
[1, ["is"]]

f("X is an acronym")
[1, ["is", "an", "acronym"]]

f("Golf is not an acronym")
0

f("Wine is not an emulator")
[1, ["an"]]

1

Rebol - 133

f: func[s][w: next take s: split s" "y: collect[foreach n s[either n/1 = w/1[take w][keep n]]]reduce either/only w: empty? w[w y][w]]

Ungolfed:

f: func [s] [
    w: next take s: split s " "
    y: collect [
        foreach n s [
            either n/1 = w/1 [take w][keep n]
        ]
    ]
    reduce either/only w: empty? w [w y][w]
]

Tested with:

foreach t [
    "RPM Package Manager"  "Wine is not an emulator"  
    "GNU is not Unix"      "Golf is not an acronym"  
    "X is a valid acronym"
][probe f t]

Output:

[true []]
[true ["an"]]
[true ["is"]]
[false]
[true ["is" "a" "valid" "acronym"]]

1

Julia - 116 bytes

f(w)=(a=split(lowercase(w));L=1;A=a[];while a!=[];a[][1]==A[1]?A=A[2:]:(L=[L,a[]]);a=a[2:];A>""||return [L,a];end;0)

Less Golfed:

f(w)=(
 a=split(lowercase(w))
 L=1
 A=a[]
 while a!=[]
  if a[][1]==A[1]
   A=A[2:]
  else
   L=[L,a[]]
  end
  a=a[2:]
  if !(A>"")
   return [L,a]
  end
 end
0)

The 0 on the end makes it output 0. Otherwise, it outputs an array containing 1 followed by the function words. For example:

julia> f("RPM Package Manager")
1-element Array{Any,1}:
 1

julia> f("Golf is not an acronym")
0

julia> f("GNU is not Unix")
2-element Array{Any,1}:
 1    
  "is"

julia> f("X is a valid acronym")
5-element Array{Any,1}:
 1         
  "is"     
  "a"      
  "valid"  
  "acronym"

1

Brachylog, 29 bytes

ḷṇ₁XhY∧X;0zpᵐz{ċ₂ˢ}ᵐZhhᵐcY∧Zt

Try it online!

Outputs the function words through the output variable if the input is a recursive acronym, and fails if it is not.

   X                             X is
ḷ                                the input lowercased
 ṇ₁                              and split on spaces,
    hY                           the first element of which is Y
      ∧                          (which is not X).
       X  z                      X zipped
        ;0                       with zero,
           pᵐ                    with all pairs permuted (creating a choicepoint),
             z                   zipped back,
              {   }ᵐ             and with both resulting lists
               ċ₂ˢ               losing all non-string elements,
                    Z            is Z.
                      hᵐ         The first elements of the elements of
                    Zh           the first element of Z
                        cY       concatenated are Y
                          ∧      (which is not Z).
                           Zt    The last element of Z is the output.

Without having to output the function words (treating this as a pure ), it comes out to just 12 bytes, because ∧Zt can be dropped for -3, Y can be replaced with . for -1, and most importantly ;0zpᵐz{ċ₂ˢ}ᵐZh can be replaced with for a whopping -13: ḷṇ₁Xh.∧X⊇hᵐc


0

Cobra - 187

def f(s as String)
    l=List<of String>(s.split)
    a=l[0]
    l.reverse
    o=0
    for c in a,for w in l.reversed
        if c==w[0]
            l.pop
            o+=1
            break
    x=o==a.length
    print x,if(x,l,'')

0

Ruby - 173

Could be better...

 f=->s{a=[];o={};s=s.split;r=true;s[0].each_char{|c|s.each{|w| w[0]=~/#{c}/i?(o[c]=1;a<<w if o[c]):(o[c]=0 if !o[c])}};r,a=false,s if o.values&[0]==[0];!r ?[r]:[r,(s-(a&a))]}

Calling the func :

p f.call('RPM Package Manager')
p f.call('Wine is not an emulator')
p f.call("GNU is not Unix")
p f.call("Golf is not an acronym")
p f.call("X is a valid acronym")

Output :

[true, []]
[true, ["an"]]
[true, ["is"]]
[false]
[true, ["is", "a", "valid", "acronym"]]

0

Java - 195

Unfortunately, Java does not have built in tuple support.

So, this is a class that stores the boolean in 'b' and the function word list in 'x'.

Here, the function is the constructor of the class.

static class R{boolean b;String[]x;R(String s){String v=" ",i="(?i)",f=s.split(v)[0],r=i+f.replaceAll("(?<=.)",".* ");if(b=(s+=v).matches(r))x=(s.replaceAll(i+"\\b["+f+"]\\S* ","")+v).split(v);}}

Test

public class RecursiveAcronyms {
public static void main(String args[]) {
    String[] tests = {
            "RPM Package Manager",
            "Wine is not an emulator",
            "GNU is not Unix",
            "Golf is not an acronym",
            "X is a valid acronym"
        };
    for (String test:tests) {
        R r = new R(test);
        System.out.print(r.b);
        if (r.b) for (String s:r.x) System.out.print(" "+s);
        System.out.print("\n");
    }
}
static class R{boolean b;String[]x;R(String s){String v=" ",i="(?i)",f=s.split(v)[0],r=i+f.replaceAll("(?<=.)",".* ");if(b=(s+=v).matches(r))x=(s.replaceAll(i+"\\b["+f+"]\\S* ","")+v).split(v);}}}

C# has tuples but I came up with this while working on my solution: just return string[]: null simply means false, empty means true and n elements means true with n function words.
Num Lock

I would like to do that too. However OP specifies that the boolean must be provided regardless. See the reply to Jan Dvorak's comment.
Vectorized

I don't care about the comments as I can't seem to spot a resulted edit in the original post. And even if i did, it clearly just says to "specify the boolean". And even in the answer itself it says "Output result can be true/false, 0/1, yes/no...+" which I might just extend at the ellipsis by "*null/not null" ...
Num Lock

0

Awk - 145

awk -v RS=' ' '{c=tolower($0)};NR==1{w=c};{t=substr(c,1,1)!=substr(w,NR-s,1);if(t){f=f" "c;s++};a=a||t};END{print a&&(s>NR-length(w))?"N":"Y|"f}'

Test:

$ cat gcp.sh
#!/bin/sh
f() {
echo "$1:"
echo "$1"|awk -v RS=' ' '{c=tolower($0)};NR==1{w=c};{t=substr(c,1,1)!=substr(w,NR-s,1);if(t){f=f" "c;s++};a=a||t};END{print a&&(s>NR-length(w))?"N":"Y|"f}'
}
f "RPM Package Manager"
f "Wine is not an emulator"
f "Wine is not an appropriate emulator"
f "GNU is not Unix"
f "Golf is not an acronym"
f "Go is not an acronym"
f "Go is a valid acronym OK"
f "X is a valid acronym"
f "YAML Ain't Markup Language"

$ ./gcp.sh
RPM Package Manager:
Y|
Wine is not an emulator:
Y| an
Wine is not an appropriate emulator:
Y| an appropriate
GNU is not Unix:
Y| is
Golf is not an acronym:
N
Go is not an acronym:
N
Go is a valid acronym OK:
Y| is a valid acronym
X is a valid acronym:
Y| is a valid acronym

YAML Ain't Markup Language:
Y|

0

Coffeescript - 144

z=(a)->g=" ";b=a.split g;c=b[0];d=[];(d.push(e);g++)for e,f in b when e[0].toLowerCase()!=c[f-g].toLowerCase();if(g+c.length==f)then{1,d}else{0}

Call it with, for instance: z "GNU is not Unix"

The compiled JS:

var z;
z = function(a) {
  var b, c, d, e, f, g, _i, _len;
  g = " ";
  b = a.split(g);
  c = b[0];
  d = [];
  for (f = _i = 0, _len = b.length; _i < _len; f = ++_i) {
    e = b[f];
    if (e[0].toLowerCase() !== c[f - g].toLowerCase()) {
      d.push(e);
      g++;
    }
  }
  if (g + c.length === f) {
    return {
      1: 1,
      d: d
    };
  } else {
    return {
      0: 0
    };
  }
};

It splits the string into words and then loops through each word. If the first character of the word doesn't match the next in the acronym, the word is stored. A counter (g) is used to track how many words have been skipped. If the number of skipped words plus the length of the acronym matches the length of the phrase, it matched, so return 1 and the skipped words. If not, it was not valid, so return 0.


0

C# - 234

Tuple<bool,string[]> f(string w) {var l=w.ToLower().Split(' ');var o=new List<string>();int n=0;var a=l[0];foreach(var t in l){if(n>=a.Length||a[n]!=t[0])o.Add(t);else n++;}var r=n>=a.Length;return Tuple.Create(r,r?o.ToArray():null);}

0

Python (108)

l=raw_input().lower().split()
a=l[0]
e=[]
for w in l:d=w[0]!=a[0];a=a[1-d:];e+=[w]*d  
b=a==''
print b,b*`e`
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.