Acronimi ricorsivi


31

Obbiettivo

Da Wikipedia :

Un acronimo ricorsivo è un acronimo che si riferisce a se stesso nell'espressione per cui rappresenta.

Il tuo obiettivo è verificare se una stringa è un acronimo ricorsivo.

  • L'acronimo è la prima parola
  • Le parole non fanno distinzione tra maiuscole e minuscole, separate da un singolo spazio.
  • La stringa fornita non contiene punteggiatura né apostrofo.
  • Solo la prima lettera di ogni parola può far parte dell'acronimo.

Devi anche dare le parole funzione . Per semplicità, ogni parola può essere considerata come una parola funzione.

Esempio

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

Puoi dare un programma completo o una funzione.
La stringa di input può essere presa da STDIN o come argomento di funzione.
Il risultato dell'output può essere vero / falso, 0/1, sì / no ...
L'elenco di parole di funzione (qualsiasi formato di elenco è valido) deve essere fornito se e solo se si tratta di un acronimo ricorsivo (anche se l'elenco è vuoto) . Non è necessario preservare la maiuscola delle parole funzione.

Criteri vincenti

Questo è un , vince il codice più corto.


4
Dobbiamo preservare la maiuscola delle parole funzione?
algoritmo

1
È accettabile avere un elenco di stringhe che accompagnano un valore False o no?
undergroundmonorail,

1
Poiché la stessa lista di parole codifica il valore booleano in base alla sua presenza, possiamo omettere il valore booleano?
John Dvorak,

5
Hurd è l'acronimo di Hird of Unix-Replacing Daemons. Hird è l'acronimo di Hurd of Interfaces Representing Depth. Perché gli esempi qui non lo capiscono e sostengono che non sono acronimi ricorsivi?
Konrad Borowski

3
@xfix, Wikipedia afferma che si tratta di acronimi reciprocamente ricorsivi .
Michael M.,

Risposte:


7

GolfScript, 51 50 caratteri

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

Probabilmente può essere ulteriormente giocato a golf. Accetta input su STDIN. Il valore booleano è 0/1.

Test online


Spiegazione:

{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, sapore .NET, 62 byte

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

Puoi provarlo qui . Se l'input è un acronimo ricorsivo, questo produrrà una corrispondenza e il gruppo di acquisizione wconterrà tutte le parole di funzione. In caso contrario, non ci sarà alcuna corrispondenza.

Questo fa di preservare capitalizzazione delle parole funzionali (ma corrisponde caso-insensibile).

Sfortunatamente, il tester non mostra l'intero stack di un gruppo di acquisizione denominato, ma se lo si utilizzava ovunque in .NET, il wgruppo lo farebbe contenere tutte le parole di funzione in ordine.

Ecco uno snippet C # per dimostrare che:

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

Ecco una breve spiegazione Sto usando i gruppi di bilanciamento di .NET per creare una pila di lettere di acronimo nel gruppo denominato c, con questo frammento

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

Il trucco è che ho bisogno della seconda lettera in cima alla pila e l'ultima in fondo. Quindi ho messo tutto questo in uno sguardo dietro che corrisponde alla posizione dopo l'acronimo. Questo aiuta, poiché .NET abbina lookbehinds da destra a sinistra, quindi trova prima l'ultima lettera.

Una volta ottenuto quello stack, abbino il resto della stringa parola per parola. O la parola inizia con la lettera in cima alla pila di acronimi. In quel caso faccio scoppiare quella lettera dallo stack:

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

Altrimenti, abbino comunque la parola e spingo sulla wpila che conterrà quindi tutte le parole funzione:

 (?<w>\w+)

Alla fine mi assicuro di aver raggiunto la fine della stringa con $e anche di aver esaurito tutte le lettere dell'acronimo, controllando che lo stack sia vuoto:

(?(c)(?!))

Provalo su ideone.


1
Grande espressione regolare, ma la domanda afferma chiaramente "Puoi dare un programma completo o una funzione ".
Spazzolino da denti

4
@toothbrush Se l'OP decide di squalificare la mia risposta in base a quello, così sia. Ma penso di poter sottolineare che si tratta di un programma completo nel linguaggio che è il sapore dell'espressione regolare di .NET (non un linguaggio completo di Turing e uno che è un po 'complicato da eseguire, ma comunque un linguaggio). In ogni caso, mi piace il fatto di averlo risolto con un approccio di pura regex, e preferirei che la risposta fosse squalificata piuttosto che distruggere quell'eleganza (se vuoi) rendendola "solo una risposta C # usando regex ".
Martin Ender,

Per me va bene. Volevo solo segnalarlo nel caso te lo fossi perso.
Spazzolino da denti

1
Mi piace. Regexes potrebbe non essere un linguaggio di programmazione completo di Turing, ma penso che questo dovrebbe contare.
Paul Draper,

@PaulDraper In effetti, non scommetterei nemmeno che il sapore regex di .NET non sia Turing completo ... i gruppi di bilanciamento e i lookbehind da destra a sinistra sono piuttosto potenti. E PCRE, ad esempio, è noto per essere Turing completo (che uno ha ricorsione, non sono sicuro che le pile in .NET siano sufficienti per emulare iterazioni arbitrarie).
Martin Ender,

11

Python (158, senza regex)

Non è che non mi piacciono le regex. È che non li conosco.

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, ho anche avuto una versione non golfata:

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 byte

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)

Crea un elenco di lettere nella prima parola dell'acronimo. Quindi, per ogni parola nella stringa completa, elimina il primo elemento di quell'elenco che abbiamo creato se è uguale alla prima lettera di quella parola. Altrimenti, aggiungi quella parola all'elenco delle parole funzione. Per l'output, restituire not a(In Python, qualsiasi elenco diverso dall'elenco vuoto è True-y e l'elenco è vuoto se si tratta di un acronimo ricorsivo) e l'elenco if not a.

Grazie a @ace per avermi aiutato a correggere un errore / salvare alcuni byte.


Su Python 2.7.3, arrivo SyntaxError: invalid syntaxalla fine della returnriga.
user12205,

@ace Huh, avrei potuto giurare che funzionasse quando l'ho provato. Devo aver cambiato qualcosa e ho dimenticato di provare di nuovo. Lavorerò su una correzione!
undergroundmonorail,

Puoi usare quello for w in s:f+=0*a.pop(0)if a and w[0]==a[0]else[w]che è più corto e non si basa sulle schede. Per quanto riguarda l' returnaffermazione, ho scoperto 0if a else(1,f)che è più breve del tuo originale.
user12205,

Oh, e se usi i punti e virgola per mettere le prime due istruzioni nella stessa riga, salvi un byte di rientro.
user12205,

1
Ho escogitato un modo per correggere l'errore, ma quando sono tornato qui per pubblicarlo lo avevi risolto maggiormente nei commenti: P
undergroundmonorail

3

Python - 154 caratteri

Primo tentativo di golf in codice. Penso che python non sia la lingua migliore per questo, date tutte le parole chiave lunghe. Inoltre, non penso che questa funzione sia infallibile. Funziona per l'input del PO, ma sono sicuro di poter escogitare eccezioni.

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 caratteri (la nuova riga e il carattere di tabulazione contano entrambi), ma puoi arrivare a 154 legittimamente rimuovendo quei due caratteri poiché nessuno dei due è effettivamente richiesto. Benvenuti in PPCG, a proposito. :)
undergroundmonorail,

3

ECMAScript 6 (105 byte):

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)

Inserisci la funzione nella console del browser Firefox, quindi chiama semplicemente la funzione, in questo modo:

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

Non del tutto conforme alle norme: The function words list ... must be given if and only if this is a recursive acronym. Questo li avviserà a prescindere.
MT0,

@ MT0 OK. Non ho notato questo requisito. Vedrò se riesco a riscriverlo.
Spazzolino da denti

@ MT0 Ho aggiornato il codice ora.
Spazzolino da denti

2

Haskell - 287 byte

Non la voce più breve (ehi, questo è Haskell, cosa ti aspettavi?), Ma è comunque molto divertente da scrivere.

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

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

Uscita prevista

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

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)

test:

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

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

Produzione:

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

1

Julia - 116 byte

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)

Meno golfato:

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)

L' 0estremità lo fa emettere 0. Altrimenti, emette un array contenente 1seguito dalle parole funzione. Per esempio:

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 byte

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

Provalo online!

Emette le parole della funzione attraverso la variabile di output se l'input è un acronimo ricorsivo, e fallisce in caso contrario.

   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.

Senza dover emettere le parole funzione (trattando questo come un puro ), arriva a soli 12 byte, perché ∧Ztpuò essere eliminato per -3, Ypuò essere sostituito con .per -1 e, soprattutto, ;0zpᵐz{ċ₂ˢ}ᵐZhpuò essere sostituito con per un enorme -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

Rubino - 173

Potrebbe essere migliore...

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

Chiamata alla funzione:

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

Produzione :

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

0

Java - 195

Sfortunatamente, Java non ha il supporto tupla integrato.

Quindi, questa è una classe che memorizza il valore booleano in 'b' e l'elenco delle parole funzione in 'x'.

Qui, la funzione è il costruttore della 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);}}

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 # ha tuple, ma mi è venuta in mente mentre lavoravo alla mia soluzione: basta tornare string[]: nullsignifica semplicemente falso, vuoto significa vero ed nelementi significa vero con nparole di funzione.
Bloc Num

Vorrei farlo anch'io. Tuttavia OP specifica che il booleano deve essere fornito indipendentemente. Vedi la risposta al commento di Jan Dvorak.
Vectorized

Non mi importa dei commenti in quanto non riesco a individuare una modifica risultante nel post originale. E anche se lo facessi , dice chiaramente di " specificare il booleano ". E anche nella risposta stessa dice " Il risultato di output può essere vero / falso, 0/1, sì / no ... +" che potrei semplicemente estendere ai puntini di sospensione di "* null / not null " ...
Num Blocca

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}

Chiamalo con, ad esempio: z "GNU is not Unix"

Il JS compilato:

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 stringa in parole e quindi scorre attraverso ogni parola. Se il primo carattere della parola non corrisponde al successivo nell'acronimo, la parola viene memorizzata. Un contatore ( g) viene utilizzato per tenere traccia di quante parole sono state ignorate. Se il numero di parole saltate più la lunghezza dell'acronimo corrisponde alla lunghezza della frase, ha trovato la corrispondenza, quindi restituisci 1 e le parole saltate. In caso contrario, non era valido, quindi restituire 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`
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.