De-parentesi di una stringa


25

Data una stringa tra parentesi corretta come input, genera un elenco di tutte le sottostringhe non vuote all'interno delle parentesi corrispondenti (o al di fuori di tutte le parentesi), con le parentesi nidificate rimosse. Ogni sottostringa dovrebbe essere la sequenza di caratteri esattamente tra le stesse parentesi corrispondenti. Le sottostringhe devono essere elencate in ordine di profondità e le sottostringhe della stessa profondità devono essere elencate nell'ordine in cui si verificano nella stringa. Supponiamo che l'input sia sempre tra parentesi correttamente.

Si può presumere che l'input contenga solo lettere e parentesi ASCII minuscole.

La tua risposta dovrebbe essere una funzione che, quando viene data una stringa, restituisce un elenco di stringhe.

Esempi:

                   'a(b)c(d)e' -> ['ace', 'b', 'd']
                   'a(b(c)d)e' -> ['ae', 'bd', 'c']
                  'a((((b))))' -> ['a', 'b']
                        'a()b' -> ['ab']
                            '' -> []
                           'a' -> ['a']
          '(((a(b)c(d)e)f)g)h' -> ['h', 'g', 'f', 'ace', 'b', 'd']
'ab(c(((d)ef()g)h()(i)j)kl)()' -> ['ab', 'ckl', 'hj', 'efg', 'i', 'd']

Vince il minor numero di byte.


Sono 'i'e 'd'nell'ordine corretto nell'ultimo caso di test?
PurkkaKoodari,

@ Pietu1998 iè nidificato meno profondamente di d.
febbraio

@feersum Oh, giusto.
PurkkaKoodari,

1
Ti dispiacerebbe consentire anche gli altri tipi di invio standard, in particolare i programmi completi? Non tutte le lingue hanno un concetto di funzioni. Per consenso predefinito, consultare meta.codegolf.stackexchange.com/a/2422/8478 e meta.codegolf.stackexchange.com/questions/2447/… .
Martin Ender,

2
@redstonerodent Il testo che tendo a usare è "Puoi scrivere un programma o una funzione, prendendo input tramite STDIN (o alternativa più vicina), argomento della riga di comando o argomento della funzione e producendo il risultato tramite STDOUT (o alternativa più vicina), valore di ritorno della funzione o parametro di funzione (out). " e nel tuo caso "L'output può essere in qualsiasi formato elenco semplice, chiaro e non ambiguo".
Martin Ender,

Risposte:


11

JavaScript ES6, 91 93 104 133 148

Modifica2 2 byte salvati grazie all'utente 81655

Modifica Utilizzo di più stringhe e meno array

Prova a eseguire lo snippet di seguito in un browser compatibile con EcmaScript 6

f=s=>[...s].map(c=>l+=c<')'||-(o[l]=(o[l]||'')+c,c<'a'),o=[],l=0)&&(o+'').match(/\w+/g)||[]

// Less golfed

u=s=>{
  o=[]; l=0;
  [...s].map(c=>{
    if (c>'(') // letters or close bracket
      o[l]=(o[l]||'')+c, // add letter or close bracket to current level string
      l-=c<'a' // if close bracket, decrement level
    else
      ++l // open bracket, increment level
  })
  o = o+'' // collapse array to comma separated string
  return o.match(/\w+/g)||[] // fetch non empty strings into an array
}

// TEST
console.log=x=>O.innerHTML+=x+'\n'

;[ 'a(b)c(d)e'                    // ['ace', 'b', 'd']
 , 'a(b(c)d)e'                    // ['ae', 'bd', 'c']
 , 'a((((b))))'                   // ['a', 'b']
 , 'a()b'                         // ['ab']
 , ''                             // []
 , 'a'                            // ['a']
 , '(((a(b)c(d)e)f)g)h'           // ['h', 'g', 'f', 'ace', 'b', 'd']
 , 'ab(c(((d)ef()g)h()(i)j)kl)()' // ['ab', 'ckl', 'hj', 'efg', 'i', 'd']
].forEach(t=>console.log(t +" -> " + f(t)))
<pre id=O></pre>


Salva 2 byte con c=>l+=c<')'||-(o[l]=(o[l]||'')+c,c<'a'),.
user81655

@ user81655 nice, thanks
edc65

8

Julia, 117 86 83 byte

v->(while v!=(v=replace(v,r"(\(((?>\w|(?1))*)\))(.*)",s"\g<3> \g<2>"))end;split(v))

È una soluzione regex.

Ungolfed:

function f(v)
  w=""
  while v!=w
    w=v
    v=replace(v,r"(\(((?>\w|(?1))*)\))(.*)",s"\g<3> \g<2>"))
  end
  split(v)
end

r"(\(((?>\w|(?1))*)\))(.*)"è una (?1)regex ricorsiva ( gruppo di reclami 1) che corrisponderà alle prime parentesi bilanciate più esterne (che non contengono parentesi sbilanciate / invertite), con il secondo gruppo che contiene tutto ciò che è racchiuso tra parentesi (escluse le parentesi stesse) e il terzo gruppo che contiene tutto dopo le parentesi (fino alla fine della stringa).

replace(v,r"...",s"\g<3> \g<2>")sposta quindi il secondo gruppo alla fine della stringa (dopo uno spazio, per fungere da delimitatore), con le parentesi corrispondenti rimosse. Esaminando fino a v == w, si assicura che la sostituzione venga ripetuta fino a quando non rimangono più parentesi. Poiché le corrispondenze vengono spostate alla fine e quindi la corrispondenza successiva vale per la prima parentesi, il risultato sarà la stringa suddivisa in ordine di profondità.

Quindi splitrestituisce tutti i componenti non bianchi della stringa sotto forma di un array di stringhe (che non hanno spazi bianchi).

Si noti che w=""viene utilizzato nel codice non golfizzato per assicurarsi che il ciclo while venga eseguito almeno una volta (tranne se la stringa di input è vuota, ovviamente) e non è necessaria nella forma golf.

Grazie a Martin Büttner per l'assistenza nel salvataggio di 3 byte.


Bene, sono arrivato alla stessa soluzione in modo indipendente a Retina. Sono 44 byte lì, ma allo stato attuale non sono consentite soluzioni a programma completo. : /
Martin Ender,

È possibile salvare tre byte utilizzando \winvece di [^()].
Martin Ender,

@ MartinBüttner - grazie. In realtà l'avevo considerato, ma ero preoccupato di aver trascurato qualcosa e che avrebbe fallito in qualche caso marginale. Se dici che va bene, però, va bene.
Glen O,

6

Python, 147 byte

def f(s):
 d=0;r=[['']for c in s]
 for c in s:
  if c=='(':d+=1;r[d]+=['']
  elif c==')':d-=1
  else:r[d][-1]+=c
 return[i for i in sum(r,[])if i]

Test unitari:

assert f('a(b)c(d)e') == ['ace', 'b', 'd']
assert f('a(b(c)d)e') == ['ae', 'bd', 'c']
assert f('a((((b))))') == ['a', 'b']
assert f('a()b') == ['ab']
assert f('') == []
assert f('a') == ['a']
assert f('(((a(b)c(d)e)f)g)h') == ['h', 'g', 'f', 'ace', 'b', 'd']
assert f('ab(c(((d)ef()g)h()(i)j)kl)()') == ['ab', 'ckl', 'hj', 'efg', 'i', 'd']

Mi piace questo puzzle; è molto carino!


4

Pyth, 32 byte

fTscR)uX0.<GJ-FqLH`()@[Hdk)Jzmkz

Suite di test

Liberamente basato sull'approccio di @ Quuxplusone. Costruisce elenchi di caratteri separati da spazi a ogni profondità, quindi li divide e filtra i gruppi vuoti. L'elenco di lavoro viene ruotato per mantenere sempre aggiornato l'elenco della profondità corrente.


4

Retina , 44 41 byte

+`\(((\w|(\()|(?<-3>.))*).(.*)
$4 $1
S_` 

Corri con la -sbandiera. Notare lo spazio alla fine dell'ultima riga.

Ho trovato questa soluzione indipendentemente da Glen O ma risulta essere identica. L'idea è di abbinare la prima coppia di parentesi, rimuoverla e inserirne il contenuto alla fine dell'output (ripetutamente). A causa della mancanza di ricorsione di .NET in regex, ho dovuto usare gruppi di bilanciamento che sono più lunghi di quattro byte.

Se non capisci la prima regex, lascia che ti riferisca alla mia risposta SO sui gruppi di bilanciamento . Poiché è garantito che l'input sia correttamente tra parentesi, possiamo salvare due byte abbinandoli )con .invece di \). Quindi abbiniamo semplicemente il resto della stringa a (.*). $4 $1prima riscrive il resto della stringa (omettendo sia le parentesi che il loro contenuto), quindi il contenuto delle parentesi dopo uno spazio. La +`dice Retina ripetere questo passaggio finché la stringa smette di variare (che avviene solo quando tutti parentesi sono stati rimossi).

Le parentesi vuote comporteranno due spazi consecutivi, quindi alla fine dividiamo l'intera stringa su spazi ( S`attiva la modalità split e la regex è un singolo spazio). L' _opzione dice a Retina di omettere parti vuote della divisione, quindi non includiamo i risultati vuoti nell'output.


3

Lisp comune, 160

(lambda(x)(labels((g(l)(cons(#1=format()"~(~{~A~}~)"(#2=remove-if'listp l))(mapcan #'g(#2#'atom l)))))(remove""(g(read-from-string(#1#()"(~A)"x))):test'equal))))

Questo potrebbe essere di quattro byte in meno se la conversione del caso non fosse necessaria. L'idea è quella di aggiungere parentesi sinistra e destra su ciascun lato della stringa di input, trattarla come un elenco, scrivere gli elementi di livello superiore dell'elenco su una stringa e quindi elaborare le liste secondarie allo stesso modo.


2

Haskell, 114 112 111 byte

')'%(h:i:t)=("":i):t++[h]
'('%l=last l:init l
c%((h:i):t)=((c:h):i):t
g x=[a|a<-id=<<foldr(%)(x>>[[""]])x,a>""]

Esempio di utilizzo: g "ab(c(((d)ef()g)h()(i)j)kl)()"-> ["ab","ckl","hj","efg","i","d"].

Sto andando indietro attraverso la stringa di input. La struttura di dati intermedia è un elenco di elenco di stringhe. L'elenco esterno è per livello e l'elenco interno è per gruppo all'interno di un livello, ad esempio [["ab"],["ckl"],["hj"],["efg","i"],["d"]](nota: l'elenco reale ha molte stringhe vuote nel mezzo). Tutto inizia con un numero di stringhe vuote pari alla lunghezza dell'input - più che sufficiente, ma gli elenchi vuoti vengono comunque filtrati. Gli elenchi esterni ruotano su (/ )o aggiungono il carattere all'elemento frontale. )avvia anche un nuovo gruppo.

Modifica: @Zgarb ha trovato un byte da salvare.


1

Sed, 90 byte

:
s/^(\w*)\((.*)\n?(.*)/\1\n\3_\2/M
s/(\n\w*_)(\w*)\)(.*)/\3\1\2/M
t
s/[_\n]+/,/g
s/,$//

Utilizza regex estesi ( -rflag), calcolati da +1 byte. Inoltre, utilizza un'estensione GNU (il Mflag sul scomando).

Esempio di utilizzo:

$ echo 'ab(c(((d)ef()g)h()(i)j)kl)()' | sed -r -f deparenthesize.sed
ab,ckl,hj,efg,i,d

Spiegazione: Poiché sed non supporta elementi come regex ricorsivi, è necessario un lavoro manuale. L'espressione è suddivisa in più righe, ognuna delle quali rappresenta un livello di profondità di annidamento. Le singole espressioni sulla stessa profondità (e quindi sulla stessa linea) sono separate da un _. Lo script funziona attraverso la stringa di input una parentesi alla volta. L'input rimanente viene sempre mantenuto alla fine della riga che corrisponde al livello di annidamento corrente.


0

Python, 161 byte

Ecco cosa mi è venuta in mente, una soluzione Python funzionale a una riga:

p=lambda s:filter(None,sum([''.join([s[i]for i in range(len(s))if s[:i+1].count('(')-s[:i+1].count(')')==d and s[i]!=')']).split('(')for d in range(len(s))],[]))

Questa sfida è stata ispirata da https://github.com/samcoppini/Definition-book , che genera una lunga stringa con la parola definita tra parentesi. Volevo scrivere un codice che mi avrebbe dato ogni frase, con la parentesi rimossa. La soluzione funzionale è troppo lenta per essere efficace su stringhe lunghe, ma le soluzioni imperative (come la soluzione di @ Quuxplusone) sono molto più veloci.

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.