Supprimer la parenthèse d'une chaîne

25

Étant donné une chaîne correctement entre parenthèses en entrée, affichez une liste de toutes les sous-chaînes non vides dans les parenthèses correspondantes (ou en dehors de toutes les parenthèses), avec les parenthèses imbriquées supprimées. Chaque sous-chaîne doit être la séquence de caractères exactement dans les mêmes parenthèses correspondantes. Les sous-chaînes doivent être répertoriées par ordre de profondeur et les sous-chaînes de la même profondeur doivent être répertoriées dans l'ordre dans lequel elles apparaissent dans la chaîne. Supposons que l'entrée est toujours correctement entre parenthèses.

Vous pouvez supposer que l'entrée ne contient que des lettres ASCII minuscules et des parenthèses.

Votre réponse doit être une fonction qui, lorsqu'elle reçoit une chaîne, renvoie une liste de chaînes.

Exemples:

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

Le moins d'octets gagne.

redstonerodent
la source
Sont 'i'et 'd'dans le bon ordre dans le dernier cas de test?
PurkkaKoodari
@ Pietu1998 iest moins profondément imbriqué que d.
feersum
@feersum Oh, c'est vrai.
PurkkaKoodari
1
Pourriez-vous également autoriser les autres types de soumission standard, en particulier les programmes complets? Toutes les langues n'ont pas un concept de fonctions. Pour le consensus par défaut, voir meta.codegolf.stackexchange.com/a/2422/8478 et meta.codegolf.stackexchange.com/questions/2447/… .
Martin Ender
2
@redstonerodent Le libellé que j'ai tendance à utiliser est "Vous pouvez écrire un programme ou une fonction, en prenant une entrée via STDIN (ou l'alternative la plus proche), un argument de ligne de commande ou un argument de fonction et en sortant le résultat via STDOUT (ou l'alternative la plus proche), la valeur de retour de la fonction ou fonction (out). " et dans votre cas "La sortie peut être dans n'importe quel format de liste plat pratique et sans ambiguïté."
Martin Ender

Réponses:

11

JavaScript ES6, 91 93 104 133 148

Edit2 2 octets enregistrés thx user81655

Modifier en utilisant plus de chaînes et moins de tableaux

Testez l'exécution de l'extrait ci-dessous dans un navigateur compatible 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>

edc65
la source
Économisez 2 octets avec c=>l+=c<')'||-(o[l]=(o[l]||'')+c,c<'a'),.
user81655
@ user81655 nice, thanks
edc65
8

Julia, 117 86 83 octets

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

C'est une solution regex.

Non golfé:

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))*)\))(.*)"est une (?1)expression régulière récursive ( groupe récursif 1) qui correspondra aux premières parenthèses équilibrées les plus externes (qui ne contiennent pas de parenthèses asymétriques / inversées), le deuxième groupe contenant tout à l'intérieur des parenthèses (non compris les parenthèses elles-mêmes) et le troisième groupe contenant tout après les parenthèses (jusqu'à la fin de la chaîne).

replace(v,r"...",s"\g<3> \g<2>")déplace ensuite le deuxième groupe à la fin de la chaîne (après un espace, pour agir comme délimiteur), les parenthèses appropriées étant supprimées. En itérant jusqu'à v == w, il est garanti que le remplacement est répété jusqu'à ce qu'il ne reste plus de parenthèses. Parce que les correspondances sont déplacées vers la fin, puis la correspondance suivante va pour la première parenthèse, le résultat sera la chaîne décomposée par ordre de profondeur.

splitRetourne ensuite tous les composants non blancs de la chaîne sous la forme d'un tableau de chaînes (qui n'ont pas d'espace blanc).

Notez que cela w=""est utilisé dans le code non golfé pour vous assurer que la boucle while s'exécute au moins une fois (sauf si la chaîne d'entrée est vide, bien sûr), et n'est pas nécessaire dans la forme golfée.

Merci à Martin Büttner pour son aide à économiser 3 octets.

Glen O
la source
Neat, je suis arrivé à la même solution indépendamment à Retina. C'est 44 octets, mais en l'état, les solutions de programme complet ne sont pas autorisées. : /
Martin Ender
Vous pouvez enregistrer trois octets en utilisant \wau lieu de [^()].
Martin Ender
@ MartinBüttner - merci. J'avais en fait envisagé cela, mais j'étais inquiet d'avoir oublié quelque chose et que cela échouerait dans certains cas extrêmes. Si vous dites que c'est bien, alors ça va.
Glen O
6

Python, 147 octets

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]

Tests unitaires:

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

J'aime ce puzzle; c'est très mignon!

Quuxplusone
la source
4

Pyth, 32 octets

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

Suite de tests

Librement basé sur l'approche de @ Quuxplusone. Construit des listes de caractères séparées par des espaces à chaque profondeur, puis les divise et filtre les groupes vides. La liste de travail est pivotée pour garder la liste de la profondeur actuelle devant à tout moment.

isaacg
la source
4

Rétine , 44 41 octets

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

Courez avec le -sdrapeau. Remarquez l'espace à la fin de la dernière ligne.

J'ai trouvé cette solution indépendamment de Glen O mais elle s'avère identique. L'idée est de faire correspondre la première paire de parenthèses, de la supprimer et d'insérer son contenu à la fin de la sortie (à plusieurs reprises). En raison du manque de récursivité de .NET dans l'expression régulière, j'ai dû utiliser des groupes d'équilibrage qui sont quatre octets de plus.

Si vous ne comprenez pas la première expression régulière, permettez-moi de vous référer à ma réponse SO sur l'équilibrage des groupes . Puisque l'entrée est garantie d'être correctement entre parenthèses, nous pouvons enregistrer deux octets en faisant correspondre )avec .au lieu de \). Ensuite, nous faisons simplement correspondre le reste de la chaîne avec (.*). $4 $1réécrit d'abord ledit reste de la chaîne (en omettant à la fois les parenthèses et leur contenu), puis le contenu des parenthèses après un espace. Le +`indique à Retina de répéter cette étape jusqu'à ce que la chaîne cesse de changer (ce qui ne se produit qu'une fois que toutes les parenthèses ont été supprimées).

Des parenthèses vides entraîneront deux espaces consécutifs, donc finalement nous séparons la chaîne entière sur les espaces ( S`active le mode de fractionnement et l'expression régulière est un espace unique). L' _option indique à Retina d'omettre les parties vides de la division, donc nous n'incluons pas les résultats vides dans la sortie.

Martin Ender
la source
3

Lisp commun, 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))))

Cela pourrait être de quatre octets de moins si la conversion de cas n'était pas nécessaire. L'idée est d'ajouter des parenthèses gauche et droite de chaque côté de la chaîne d'entrée, de la traiter comme une liste, d'écrire les éléments de niveau supérieur de la liste dans une chaîne, puis de traiter les sous-listes de la même manière.

Joshua Taylor
la source
2

Haskell, 114 112 111 octets

')'%(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>""]

Exemple d'utilisation: g "ab(c(((d)ef()g)h()(i)j)kl)()"-> ["ab","ckl","hj","efg","i","d"].

Je recule dans la chaîne d'entrée. La structure de données intermédiaire est une liste de listes de chaînes. La liste externe est par niveau et la liste interne est par groupe dans un niveau, par exemple [["ab"],["ckl"],["hj"],["efg","i"],["d"]](note: la vraie liste a beaucoup de chaînes vides entre les deux). Tout commence par un nombre de chaînes vides égal à la longueur de l'entrée - plus que suffisant, mais les listes vides sont quand même filtrées. Les listes externes tournent sur (/ )ou ajoutent le caractère à l'élément frontal. )démarre également un nouveau groupe.

Edit: @Zgarb a trouvé un octet à enregistrer.

nimi
la source
1

Sed, 90 octets

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

Utilise des expressions rationnelles étendues ( -rindicateur), représentées par +1 octet. En outre, cela utilise une extension GNU (l' Mindicateur sur la scommande).

Exemple d'utilisation:

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

Explication: Étant donné que sed ne prend pas en charge les éléments tels que les expressions rationnelles récursives, un travail manuel est requis. L'expression est divisée en plusieurs lignes, chacune représentant un niveau de profondeur d'imbrication. Les expressions individuelles sur la même profondeur (et donc sur la même ligne) sont séparées par un _. Le script fonctionne à travers la chaîne d'entrée un crochet à la fois. L'entrée restante est toujours conservée à la fin de la ligne qui correspond au niveau d'imbrication actuel.

matz
la source
0

Python, 161 octets

Voici ce que j'ai trouvé, une solution python fonctionnelle à une ligne:

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

Ce défi a été inspiré par https://github.com/samcoppini/Definition-book , qui génère une longue chaîne avec un mot défini entre parenthèses. Je voulais écrire du code qui me donnerait chaque phrase, sans parenthèses supprimées. La solution fonctionnelle est trop lente pour être efficace sur de longues chaînes, mais les solutions impératives (comme la solution de @ Quuxplusone) sont beaucoup plus rapides.

redstonerodent
la source