Acrónimos recursivos

31

Objetivo

De Wikipedia :

Un acrónimo recursivo es un acrónimo que se refiere a sí mismo en la expresión que representa.

Su objetivo es verificar si una cadena es un acrónimo recursivo.

  • El acrónimo es la primera palabra.
  • Las palabras no distinguen entre mayúsculas y minúsculas, separadas con un solo espacio.
  • La cadena dada no contiene ningún signo de puntuación ni apóstrofe.
  • Solo la primera letra de cada palabra puede ser parte del acrónimo.

También debe dar las palabras de función . Por simplicidad, cada palabra puede considerarse como una palabra de función.

Ejemplo

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

Puedes dar un programa completo o una función.
La cadena de entrada puede tomarse de STDIN o como un argumento de función.
El resultado de salida puede ser verdadero / falso, 0/1, sí / no ...
La lista de palabras de función (cualquier formato de lista es válida) debe darse si y solo si se trata de un acrónimo recursivo (incluso si la lista está vacía) . No tiene que preservar la capitalización de las palabras de función.

Criterios ganadores

Este es un , el código más corto gana.

Michael M.
fuente
44
¿Tenemos que preservar la capitalización de las palabras de función?
algoritmshark
1
¿Es aceptable tener una lista de cadenas que acompañan a un valor falso, o no?
undergroundmonorail
1
Dado que la lista de palabras codifica el valor booleano por su presencia, ¿podemos omitir el valor booleano?
John Dvorak
55
Hurd significa Hird of Unix-Replacing Daemons. Hird significa Hurd of Interfaces que representa la profundidad. ¿Por qué los ejemplos aquí no entienden eso y afirman que no son siglas recursivas?
Konrad Borowski
3
@xfix, wikipedia afirma que esos son acrónimos recursivos mutuos .
Michael M.

Respuestas:

7

GolfScript, 51 50 caracteres

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

Probablemente se pueda jugar más al golf. Toma entrada en STDIN. El booleano es 0/1.

Prueba en línea


Explicación:

{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
Volatilidad
fuente
22

Regex, sabor .NET, 62 bytes

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

Puedes probarlo aquí . Si la entrada es un acrónimo recursivo, esto generará una coincidencia y el grupo de captura wcontendrá todas las palabras de función. Si no es así, entonces no habrá coincidencia.

Esto hace preservar la capitalización de las palabras de función (pero coincide con mayúsculas y minúsculas).

Por desgracia, el probador no muestra toda la pila de un grupo de captura de llamada, pero si se ha utilizado en cualquier lugar de .NET, el wgrupo podría contener todas las palabras de función en orden.

Aquí hay un fragmento de C # para demostrar 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);
}

Aquí hay una explicación rápida. Estoy usando los grupos de equilibrio de .NET para construir una pila de letras acrónimas en el grupo nombrado c, con este fragmento

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

El truco es que necesito la segunda letra en la parte superior de la pila y la última en la parte inferior. Así que puse todo esto en una retrospectiva que coincide con la posición después del acrónimo. Esto ayuda, porque .NET hace coincidir los mirar hacia atrás de derecha a izquierda, por lo que primero encuentra la última letra.

Una vez que obtuve esa pila, hago coincidir el resto de la cadena palabra por palabra. O bien, la palabra comienza con la letra en la parte superior de la pila de siglas. En ese caso, saco esa letra de la pila:

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

De lo contrario, coincido con la palabra de todos modos y empujo a la wpila que contendrá todas las palabras de función:

 (?<w>\w+)

Al final, me aseguro de llegar al final de la cadena $y también me aseguro de haber usado todas las letras del acrónimo, verificando que la pila esté vacía:

(?(c)(?!))

Pruébalo en ideone.

Martin Ender
fuente
1
Gran expresión regular, pero la pregunta dice claramente "Puedes dar un programa completo o una función ".
Cepillo de dientes
44
@toothbrush Si el OP decide descalificar mi respuesta en base a eso, que así sea. Pero creo que podría señalar que este es un programa completo en el lenguaje que es el sabor de expresión regular de .NET (no es un lenguaje completo de Turing, y es un poco engorroso de ejecutar, pero un lenguaje de todos modos). En cualquier caso, me gusta el hecho de que lo resolví con un enfoque de regex puro, y prefiero descalificar la respuesta que destruir esa "elegancia" (si lo desea) convirtiéndola en "solo una respuesta C # usando regex ".
Martin Ender
Eso está bien para mí. Solo quería señalarlo en caso de que te lo hayas perdido.
Cepillo de dientes
1
Me gusta. Regexes puede no ser un lenguaje de programación completo de Turing, pero creo que esto debería contar.
Paul Draper
@PaulDraper De hecho, ni siquiera apostaría a que el sabor regex de .NET no esté completo ... los grupos de equilibrio y las miradas de derecha a izquierda son bastante poderosas. Y PCRE, por ejemplo, se sabe que Turing está completo (ese tiene recursividad, no estoy seguro de que las pilas en .NET sean suficientes para emular iteraciones arbitrarias).
Martin Ender
11

Python (158, sin expresión regular)

No es que no me gusten las expresiones regulares. Es que no los conozco.

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)

Oh, también tenía una versión sin golf:

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

Hace una lista de letras en la primera palabra del acrónimo. Luego, por cada palabra en la cadena completa, elimine el primer elemento de esa lista que hicimos si es igual a la primera letra de esa palabra. De lo contrario, agregue esa palabra a la lista de palabras de función. Para generar, regrese not a(en python, cualquier lista que no sea la lista vacía es True-y, y la lista está vacía si es un acrónimo recursivo) y la lista si not a.

Gracias a @ace por ayudarme a corregir un error / guardar algunos bytes.

monorraíl subterráneo
fuente
En Python 2.7.3, llego SyntaxError: invalid syntaxal final de la returnlínea.
usuario12205
@ace Huh, podría haber jurado que funcionó cuando lo probé. Debo haber cambiado algo y me olvidé de probar nuevamente. ¡Trabajaré en una solución!
undergroundmonorail
Puede usar el for w in s:f+=0*a.pop(0)if a and w[0]==a[0]else[w]que es más corto y no depende de pestañas. En cuanto a la returndeclaración, encontré 0if a else(1,f)que es más corta que la original.
user12205
Ah, y si usa punto y coma para poner las dos primeras declaraciones en la misma línea, guarda un byte de sangría.
usuario12205
1
Descubrí una forma de corregir el error, pero cuando volví aquí para publicarlo, lo había descifrado más en los comentarios: P
undergroundmonorail
3

Python - 154 caracteres

Primer intento de código de golf. Creo que Python no es el mejor lenguaje para él, dadas todas las palabras clave largas. Además, no creo que esta función sea infalible. Funciona para la entrada del OP, pero estoy seguro de que podría pensar en excepciones.

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
La obesidad
fuente
Cuento 156 caracteres (tanto la nueva línea como el carácter de tabulación cuentan), pero puede reducirlo a 154 legítimamente eliminando esos dos caracteres, ya que ninguno de ellos es realmente necesario. Bienvenido a PPCG, por cierto. :)
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)

Ingrese la función en la consola del navegador de Firefox y luego simplemente llame a la función, así:

f('ABC Black Cats')     // 1,,
f('ABC is Black Cats')  // 1,IS,,
f('ABC Clapping Cats')  // 0
Cepillo de dientes
fuente
No acaba de cumplir con las normas: The function words list ... must be given if and only if this is a recursive acronym. Esto los alertará independientemente.
MT0
@ MT0 OK. No noté ese requisito. Veré si puedo reescribirlo.
Cepillo de dientes
@ MT0 He actualizado el código ahora.
Cepillo de dientes
2

Haskell - 287 bytes

No es la entrada más corta (hey, este es Haskell, ¿qué esperabas?), Pero sigue siendo muy divertido de escribir.

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

Probado con

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

Rendimiento esperado

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

Sin golf

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

Pruebas:

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

Sin golf:

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

Probado con:

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]

Salida:

[true []]
[true ["an"]]
[true ["is"]]
[false]
[true ["is" "a" "valid" "acronym"]]
draegtun
fuente
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 golfizado:

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)

El 0en el extremo hace que salga 0. De lo contrario, genera una matriz que contiene 1seguida de las palabras de función. Por ejemplo:

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"
Glen O
fuente
1

Brachylog , 29 bytes

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

Pruébalo en línea!

Emite las palabras de función a través de la variable de salida si la entrada es un acrónimo recursivo y falla si no lo es.

   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.

Sin tener que emitir las palabras de función (tratando esto como un puro ), sale a solo 12 bytes, porque ∧Ztse puede descartar para -3,Y se puede reemplazar .por -1 y, lo más importante, ;0zpᵐz{ċ₂ˢ}ᵐZhse puede reemplazar por un enorme -13:ḷṇ₁Xh.∧X⊇hᵐc

Cadena no relacionada
fuente
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,'')
Οurous
fuente
0

Rubí - 173

Podría ser mejor...

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

Llamando a la 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")

Salida:

[true, []]
[true, ["an"]]
[true, ["is"]]
[false]
[true, ["is", "a", "valid", "acronym"]]
onionpsia
fuente
0

Java - 195

Desafortunadamente, Java no tiene soporte de tuplas integrado.

Entonces, esta es una clase que almacena el booleano en 'b' y la lista de palabras de función en 'x'.

Aquí, la función es el constructor de la clase.

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

Prueba

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);}}}
Vectorizado
fuente
C # tiene tuplas pero se me ocurrió esto mientras trabajaba en mi solución: solo regreso string[]: nullsimplemente significa falso, vacío significa verdadero y nelementos significa verdadero con npalabras de función.
Num Lock
Me gustaría hacer eso también. Sin embargo, OP especifica que el booleano se debe proporcionar independientemente. Ver la respuesta al comentario de Jan Dvorak.
Vectorizado
No me importan los comentarios, ya que parece que no puedo ver una edición resultante en la publicación original. E incluso si lo hiciera , claramente dice " especificar el booleano ". E incluso en la respuesta en sí dice " El resultado de salida puede ser verdadero / falso, 0/1, sí / no ... +" que podría extender en los puntos suspensivos con "* null / not null " ...
Num Bloqueo
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}'

Prueba:

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

Llámalo con, por ejemplo: z "GNU is not Unix"

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

Divide la cadena en palabras y luego recorre cada palabra. Si el primer carácter de la palabra no coincide con el siguiente en el acrónimo, la palabra se almacena. Un contador ( g) se utiliza para rastrear cuántas palabras se han omitido. Si el número de palabras omitidas más la longitud del acrónimo coincide con la longitud de la frase, coincide, por lo que devuelve 1 y las palabras omitidas. Si no, no fue válido, por lo tanto, devuelva 0.

Johno
fuente
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
fuente
0

Pitón (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
fuente