Рекурсивные аббревиатуры

31

Задача

Из Википедии :

Рекурсивная аббревиатура - это аббревиатура, которая относится к самому себе в выражении, за которым оно стоит.

Ваша цель - проверить, является ли строка рекурсивной аббревиатурой.

  • Акроним это первое слово
  • Слова не чувствительны к регистру, разделены одним пробелом.
  • Данная строка не содержит знаков препинания и апострофа.
  • Только первая буква каждого слова может быть частью аббревиатуры.

Вы также должны дать функциональные слова . Для простоты каждое слово можно рассматривать как функциональное слово.

пример

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"] }  

Вы можете дать полную программу или функцию.
Входная строка может быть взята из STDIN или в качестве аргумента функции.
Выходной результат может быть true / false, 0/1, yes / no ...
Список функциональных слов (любой формат списка допустим) должен быть задан тогда и только тогда, когда это рекурсивная аббревиатура (даже если список пуст) , Вам не нужно сохранять заглавные буквы функциональных слов.

Критерии победы

Это , самый короткий код выигрывает.

Майкл М.
источник
4
Нужно ли сохранять заглавные буквы функциональных слов?
алгоритмистика
1
Допустимо ли иметь список строк, сопровождающих значение False, или нет?
подземный
1
Поскольку сам список слов кодирует логическое значение по его наличию, можем ли мы опустить логическое значение?
Джон Дворжак
5
Hurd расшифровывается как Hird of Unix-Replacing Daemons. Hird означает Hurd of Interfaces, представляющих глубину. Почему приведенные здесь примеры не понимают этого и утверждают, что это не рекурсивные аббревиатуры?
Конрад Боровски
3
@xfix, Википедия утверждает, что это взаимно рекурсивные аббревиатуры.
Майкл М.

Ответы:

7

GolfScript, 51 50 символов

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

Это, вероятно, можно играть в гольф дальше. Принимает участие в STDIN. Логическое значение равно 0/1.

Тест онлайн


Объяснение:

{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, .NET аромат, 62 байта

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

Вы можете проверить это здесь . Если ввод является рекурсивной аббревиатурой, это приведет к совпадению, и группа захвата wбудет содержать все функциональные слова. Если это не так, то совпадения не будет.

это делает сохранить капитализацию функции слов (но соответствует регистронезависимо).

К сожалению, тестер не отображает весь стек именованной группы захвата, но если вы использовали его где-нибудь в .NET, w группа будет содержать все функциональные слова по порядку.

Вот фрагмент кода C #, чтобы доказать это:

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

Вот краткое объяснение. Я использую балансирующие группы .NET для построения стека букв аббревиатуры в именованной группе cс этим фрагментом

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

Хитрость в том, что мне нужна вторая буква вверху стека и последняя внизу. Таким образом, я помещаю все это в вид сзади, который соответствует позиции после аббревиатуры. Это помогает, потому что .NET совпадает со взглядами справа налево, поэтому сначала встречается последняя буква.

Получив этот стек, я сопоставляю остальную часть строки слово в слово. Либо слово начинается с буквы в верхней части стека акронимов. В этом случае я выталкиваю это письмо из стека:

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

В противном случае, я все равно сопоставляю слово и помещаю его в wстек, который будет содержать все служебные слова:

 (?<w>\w+)

В конце я $проверяю, достиг ли я конца строки, а также проверяю, что я использовал все буквы от аббревиатуры, проверяя, что стек пуст:

(?(c)(?!))

Проверьте это на ideone.

Мартин Эндер
источник
1
Отличное регулярное выражение, но в вопросе четко говорится: «Вы можете дать полную программу или функцию ».
Зубная щетка
4
@toothbrush Если ОП решит дисквалифицировать мой ответ на основании этого, пусть будет так. Но я думаю, что мог бы подчеркнуть, что это полная программа на языке, который является разновидностью регулярных выражений .NET (не полный язык Тьюринга, а немного трудоемкий для запуска, но, тем не менее, язык). В любом случае, мне нравится тот факт, что я решил это с помощью подхода регулярных выражений, и я бы предпочел дисквалифицировать ответ, чем уничтожить эту «элегантность» (если хотите), сделав ее «просто ответом на C # с использованием регулярных выражений». ».
Мартин Эндер
Я не против. Я просто хотел указать на это, если вы пропустили это.
Зубная щетка
1
Мне это нравится. Регулярные выражения могут не быть полным языком программирования по Тьюрингу, но я думаю, что это должно учитываться.
Пол Дрейпер
@PaulDraper На самом деле, я бы даже не поспорил на то, что вкус регулярных выражений в .NET не завершен по Тьюрингу ... уравновешивающие группы и подходящие взгляды справа налево довольно мощные. Например, известно, что PCRE завершен по Тьюрингу (у него рекурсия, я не уверен, что стеки в .NET достаточны для эмуляции произвольной итерации).
Мартин Эндер
11

Python (158, без регулярных выражений)

Дело не в том, что я не люблю регулярные выражения. Это то, что я их не знаю.

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)

О, у меня также была версия без гольфа:

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
ɐɔıʇǝɥʇuʎs
источник
5

Python 2.7 - 131 126 байт

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)

Составляет список букв в первом слове аббревиатуры. Затем для каждого слова в полной строке избавьтесь от первого элемента этого списка, который мы создали, если он совпадает с первой буквой этого слова. В противном случае добавьте это слово в список служебных слов. Для вывода верните not a(в python любой список, кроме пустого списка, равен True-y, а список пуст, если это рекурсивная аббревиатура) и список if not a.

Спасибо @ace за помощь в исправлении ошибки / сохранении некоторых байтов.

undergroundmonorail
источник
На Python 2.7.3 я получаю SyntaxError: invalid syntaxв конце returnстроки.
user12205
@ace Да, я мог бы поклясться, что это сработало, когда я проверял это. Должно быть, я что-то изменил и забыл проверить снова. Я буду работать над исправлением!
подземный
Вы можете использовать, for w in s:f+=0*a.pop(0)if a and w[0]==a[0]else[w]который короче и не зависит от вкладок. Что касается returnзаявления, я нашел, 0if a else(1,f)который короче, чем ваш оригинал.
user12205
Да, и если вы используете точки с запятой для помещения первых двух операторов в одну строку, вы сохраняете один байт отступа.
user12205
1
Я нашел способ исправить ошибку, но когда я вернулся сюда, чтобы опубликовать его, вы добавили его в комментарии: P
undergroundmonorail
3

Python - 154 символа

Первая в истории попытка игры в гольф. Я думаю, что Python не лучший язык для него, учитывая все длинные ключевые слова. Кроме того, я не думаю, что эта функция надежна. Это работает для ввода ОП, но я уверен, что могу придумать исключения.

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
Obversity
источник
Я считаю 156 символов (символ новой строки и символ табуляции оба считаются), но вы можете довести его до 154 законно, удалив эти два символа, поскольку ни один из них на самом деле не требуется. Добро пожаловать в PPCG, кстати. :)
подземный
3

ECMAScript 6 (105 байт):

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)

Введите функцию в консоль браузера Firefox, а затем просто вызовите функцию, например так:

f('ABC Black Cats')     // 1,,
f('ABC is Black Cats')  // 1,IS,,
f('ABC Clapping Cats')  // 0
зубная щетка
источник
Не совсем соответствует правилам The function words list ... must be given if and only if this is a recursive acronym. Это предупредит их независимо.
MT0
@ MT0 ОК. Я не заметил этого требования. Я посмотрю, смогу ли я переписать это.
Зубная щетка
@ MT0 Я обновил код сейчас.
Зубная щетка
2

Haskell - 287 байт

Не самая короткая запись (эй, это Haskell, что ты ожидал?), Но все же очень интересно писать.

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

Протестировано с

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

Ожидаемый результат

[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
gxtaillon
источник
2

JavaScript (ECMAScript 6) - 97 символов

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)

тесты:

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"]]
mt0
источник
1

Реболь - 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]
]

Протестировано с:

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]

Выход:

[true []]
[true ["an"]]
[true ["is"]]
[false]
[true ["is" "a" "valid" "acronym"]]
draegtun
источник
1

Юлия - 116 байт

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)

Меньше гольфа

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)

Значение 0on в конце выводит 0. В противном случае выводится массив, содержащий 1слова функций. Например:

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

Брахилог , 29 байт

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

Попробуйте онлайн!

Выводит функциональные слова через выходную переменную, если вход является рекурсивной аббревиатурой, и завершается ошибкой, если это не так.

   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.

Без необходимости выводить слова функций (рассматривая это как чисто ), получается всего 12 байтов, потому что ∧Ztможет быть отброшено для -3, Yможет быть заменено .на -1 и, что наиболее важно, ;0zpᵐz{ċ₂ˢ}ᵐZhможет быть заменено на колоссальныеḷṇ₁Xh.∧X⊇hᵐc

Несвязанная строка
источник
0

Кобра - 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,'')
Οurous
источник
0

Рубин - 173

Могло быть лучше...

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

Вызов функции:

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

Выход :

[true, []]
[true, ["an"]]
[true, ["is"]]
[false]
[true, ["is", "a", "valid", "acronym"]]
onionpsy
источник
0

Ява - 195

К сожалению, Java не имеет встроенной поддержки кортежей.

Итак, это класс, который хранит логическое значение в «b» и список функциональных слов в «x».

Здесь функция является конструктором класса.

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

Тест

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 # есть кортежи, но я придумал это, работая над своим решением: просто return string[]: nullпросто означает false, пустой означает true, а nelements означает true с nфункциональными словами.
Num Lock
Я бы тоже хотел это сделать. Однако OP указывает, что логическое значение должно быть предоставлено независимо. Смотрите ответ на комментарий Яна Дворака.
Векторизовано
Мне плевать на комментарии, так как я не могу заметить результат редактирования в исходном сообщении. И даже если бы я это сделал , он ясно говорит « указать логическое значение ». И даже в самом ответе говорится: « Выходной результат может быть истинным / ложным, 0/1, да / нет ... +», который я мог бы просто расширить на многоточии на «* null / not null » ...
Num Блокировка
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}'

Тест:

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

Назовите это, например: z "GNU is not Unix"

Скомпилированный 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
    };
  }
};

Он разбивает строку на слова, а затем перебирает каждое слово. Если первый символ слова не соответствует следующему в аббревиатуре, слово сохраняется. Счетчик ( g) используется для отслеживания количества пропущенных слов. Если количество пропущенных слов плюс длина аббревиатуры совпадает с длиной фразы, она совпадает, поэтому верните 1 и пропущенные слова. Если нет, то это было недействительно, поэтому верните 0.

Johno
источник
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);}
Grax32
источник
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`
XNOR
источник