Acrônimos recursivos


31

Objetivo

Da Wikipedia :

Um acrônimo recursivo é um acrônimo que se refere a si mesmo na expressão para a qual ele representa.

Seu objetivo é verificar se uma string é um acrônimo recursivo.

  • O acrônimo é a primeira palavra
  • As palavras não diferenciam maiúsculas de minúsculas, separadas por um único espaço.
  • A sequência especificada não contém pontuação nem apóstrofo.
  • Somente a primeira letra de cada palavra pode fazer parte da sigla.

Você também deve fornecer as palavras de função . Para simplificar, cada palavra pode ser considerada como uma palavra de função.

Exemplo

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

Você pode dar um programa completo ou uma função.
A cadeia de entrada pode ser obtida de STDIN ou como argumento de função.
O resultado da saída pode ser verdadeiro / falso, 0/1, sim / não ...
A lista de palavras da função (qualquer formato da lista é válido) deve ser fornecida se e somente se for um acrônimo recursivo (mesmo que a lista esteja vazia) . Você não precisa preservar a capitalização das palavras de função.

Critérios de vitória

Este é um , o código mais curto vence.


4
Temos que preservar a capitalização das palavras de função?
— algorithmshark

1
É aceitável ter uma lista de cadeias acompanhando um valor False ou não?
— Undergroundmonorail

1
Como a própria lista de palavras codifica o valor booleano por sua presença, podemos omitir o valor booleano?
— John Dvorak

5
Hurd é a sigla de Hird of Unix-Replacing Daemons. Hird significa Hurd of Interfaces Representing Depth. Por que os exemplos aqui não entendem isso e afirmam que não são acrônimos recursivos?
— Konrad Borowski

3
@xfix, a wikipedia afirma que esses são acrônimos mutuamente recursivos .
— Michael M.

Respostas:


7

GolfScript, 51 50 caracteres

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

Provavelmente pode ser jogado mais. Recebe entrada em STDIN. O booleano é 0/1.

Teste on-line


Explicação:

{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, sabor .NET, 62 bytes

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

Você pode testá-lo aqui . Se a entrada for um acrônimo recursivo, isso produzirá uma correspondência e o grupo de captura wconterá todas as palavras de função. Caso contrário, não haverá correspondência.

Isso faz preservar a capitalização das palavras de função (mas corresponde caso insensível).

Infelizmente, o testador não exibe toda a pilha de um grupo de captura de chamada, mas se você usou-o em qualquer lugar .NET, o wgrupo iria conter todas as palavras de função em ordem.

Aqui está um trecho de código C # para provar que:

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

Aqui está uma explicação rápida. Estou usando os grupos de balanceamento do .NET para criar uma pilha das letras de sigla no grupo nomeado c, com esse snippet

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

O truque é que eu preciso da segunda letra no topo da pilha e a última na parte inferior. Então eu coloquei tudo isso em um lookbehind que corresponde à posição após a sigla. Isso ajuda, porque o .NET corresponde à aparência da direita para a esquerda e, portanto, encontra a última letra primeiro.

Depois de obter essa pilha, ligo o resto da string palavra por palavra. A palavra começa com a letra no topo da pilha de acrônimos. Nesse caso, eu tiro essa letra da pilha:

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

Caso contrário, eu igualo a palavra de qualquer maneira e empurro a wpilha que conterá todas as palavras de função:

 (?<w>\w+)

No final, certifico-me de que cheguei ao final da string com $e também verifiquei se todas as letras do acrônimo foram usadas, verificando se a pilha está vazia:

(?(c)(?!))

Teste em ideone.


1
Ótima expressão regular, mas a pergunta afirma claramente "Você pode dar um programa completo ou uma função ".
— Escova de dentes

4
@toothbrush Se o OP decidir desqualificar minha resposta com base nisso, que assim seja. Mas acho que posso afirmar que este é um programa completo na linguagem que é o sabor da expressão regular do .NET (não é uma linguagem completa de Turing e é um pouco complicada de executar, mas, mesmo assim, é uma linguagem). De qualquer forma, gosto do fato de ter resolvido isso com uma abordagem de pura regex e prefiro ter a resposta desqualificada do que destruir essa "elegância" (se você quiser), tornando-a "apenas uma resposta em C # usando regex "
— Martin Ender

Tudo bem para mim. Eu só queria salientar se você perdeu.
— Escova de dentes

1
Eu gosto disso. Regexes podem não ser uma linguagem de programação completa de Turing, mas acho que isso deve contar.
— Paul Draper

@PaulDraper Na verdade, eu nem apostaria que o sabor do regex do .NET não fosse Turing completo ... os grupos de equilíbrio e os lookbehinds da direita para a esquerda são muito poderosos. E o PCRE, por exemplo, é conhecido por ser Turing completo (aquele com recursão, não tenho certeza de que as pilhas no .NET sejam suficientes para emular iterações arbitrárias).
— Martin Ender

11

Python (158, sem regex)

Não é que eu não goste de expressões regulares. É que eu não os conheço.

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)

Ah, eu também tinha uma versão não destruída:

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)

Faz uma lista de letras na primeira palavra da sigla. Em seguida, para cada palavra na sequência completa, livre-se do primeiro elemento da lista que fizemos, se for o mesmo que a primeira letra dessa palavra. Caso contrário, adicione essa palavra à lista de palavras de função. Para saída, retorne not a(em python, qualquer lista que não seja a lista vazia é True-y, e a lista está vazia se for um acrônimo recursivo) e a lista se not a.

Agradeço ao @ace por me ajudar a corrigir um erro / salvar alguns bytes.


No Python 2.7.3, chego SyntaxError: invalid syntaxao final da returnlinha.
— User12205

@ace Huh, eu poderia jurar que funcionou quando o testei. Eu devo ter mudado alguma coisa e esqueci de testar novamente. Vou trabalhar em uma correção!
— Undergroundmonorail

Você pode usar o for w in s:f+=0*a.pop(0)if a and w[0]==a[0]else[w]que é mais curto e não depende de guias. Quanto à returndeclaração, descobri 0if a else(1,f)qual é mais curta que o original.
— User12205

Ah, e se você usar ponto e vírgula para colocar as duas primeiras instruções na mesma linha, você salvará um byte de recuo.
— User12205

1
Eu descobri uma maneira de corrigir o erro, mas quando voltei aqui para postá-lo você tinha golfed-lo mais nos comentários: P
— undergroundmonorail

3

Python - 154 caracteres

Primeira tentativa de código de golfe. Estou pensando que python não é a melhor linguagem para isso, considerando todas as palavras-chave longas. Além disso, não acho que essa função seja infalível. Funciona para a entrada do OP, mas tenho certeza de que poderia pensar em exceções.

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

Conto 156 caracteres (a nova linha e o caractere de tabulação contam), mas você pode reduzi-lo para 154 legitimamente removendo esses dois caracteres, pois nenhum deles é realmente necessário. Bem-vindo ao 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)

Digite a função no console do navegador Firefox e, em seguida, basta chamar a função, assim:

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

Não chega a cumprir as regras: The function words list ... must be given if and only if this is a recursive acronym. Isso os alertará independentemente.
— MT0 27/05

@ MT0 OK. Eu não percebi esse requisito. Vou ver se consigo reescrevê-lo.
— Escova de dentes

@ MT0 Atualizei o código agora.
— Escova de dentes

2

Haskell - 287 bytes

Não é a entrada mais curta (ei, é Haskell, o que você esperava?), Mas ainda assim é muito divertido escrever.

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

Testado com

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

Saída esperada

[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 caracteres

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)

Testes:

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

Testado com:

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]

Saída:

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

Menos Golfe:

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)

O 0no final faz com que seja a saída 0. Caso contrário, ele gera uma matriz contendo 1seguidos pelas palavras da função. Por exemplo:

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

Braquilog , 29 bytes

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

Experimente online!

Emite as palavras de função através da variável de saída se a entrada for um acrônimo recursivo e falhará se não for.

   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.

Sem precisar produzir as palavras de função (tratando isso como um puro ), ele sai para apenas 12 bytes, porque ∧Ztpode ser descartado para -3, Ypode ser substituído .por -1 e, o mais importante, ;0zpᵐz{ċ₂ˢ}ᵐZhpode ser substituído por ⊇for um gritante -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

Poderia ser melhor...

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

Chamando a função:

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

Saída:

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

0

Java - 195

Infelizmente, o Java não possui suporte à tupla.

Portanto, essa é uma classe que armazena o booleano em 'b' e a lista de palavras da função em 'x'.

Aqui, a função é o construtor da classe.

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

Teste

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 # tem tuplas, mas eu vim com isso enquanto trabalhava na minha solução: basta retornar string[]: nullsimplesmente significa falso, vazio significa verdadeiro e nelementos significa verdadeiro com npalavras de função.
— Num Lock

Eu também gostaria de fazer isso. No entanto, o OP especifica que o booleano deve ser fornecido independentemente. Veja a resposta ao comentário de Jan Dvorak.
— Vetorizado

Não ligo para os comentários, pois não consigo identificar uma edição resultante na postagem original. E mesmo se eu fiz , claramente diz apenas " especificar o booleano ". E mesmo na resposta em si, diz " O resultado da saída pode ser verdadeiro / falso, 0/1, sim / não ... +", que eu poderia estender nas reticências por "* null / not null " ...
— Num Bloquear

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

Teste:

$ 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

Café - 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}

Ligue com, por exemplo: z "GNU is not Unix"

O JS compilado:

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

Ele divide a string em palavras e depois percorre cada palavra. Se o primeiro caractere da palavra não corresponder ao próximo no acrônimo, a palavra será armazenada. Um contador ( g) é usado para rastrear quantas palavras foram puladas. Se o número de palavras ignoradas mais o comprimento da sigla corresponder à duração da frase, ela corresponderá, retorne 1 e as palavras ignoradas. Caso contrário, não era válido, então retorne 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`
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.