Écrivez un programme qui remplace par des espaces les accolades dans les cas où les accolades dans les lieux provoquent une stase

17

Vous êtes chef de projet. Un jour, l'un de vos programmeurs est devenu fou (ce n'est pas de votre faute ) et a pris toutes les expressions dans la base de code et leur a ajouté des crochets aléatoires, avant de quitter sur le champ, se plaignant de votre incompétence (ce n'est pas non plus votre faute ). Ce serait une solution facile, cependant, pour une raison quelconque, vous n'utilisez pas le contrôle de révision (ce n'est absolument pas votre faute ). Et pour une raison quelconque, aucun des autres programmeurs ne veut passer par chaque expression pour corriger les crochets incompatibles ( d'ailleurs, ce n'est pas votre faute ). Les programmeurs de nos jours, vous pensez à vous-même. Vous devrez le faire vous-même. L'horreur! De telles tâches étaient censées être sous vous ...

L'entrée sera une seule ligne, qui contiendra un certain nombre de crochets gauche ( ( [ {) et de crochets droit ( ) ] }). Il peut également, mais pas toujours, contenir des commentaires ( /* */) et des littéraux de chaîne ( " "ou ' ') et divers chiffres, lettres ou symboles.

Il y aura au moins une parenthèse (en dehors d'un commentaire ou d'un littéral de chaîne) qui n'a pas d'opposé corrosif (en dehors d'un commentaire ou d'un littéral de chaîne). Par exemple, un errant }sans a {priori. Un autre exemple: un (qui n'en a pas )après. Votre programme remplacera par un espace le nombre minimum de parenthèses requises pour faire correspondre les parenthèses.

Exemples:

(4 + (2 + 3))]==> (4 + (2 + 3)) (le crochet à la fin)
][][[]]==> [][[]](le crochet au début)
("Hel(o!"))==> ("Hel(o!") (la parenthèse à la fin)
( /* )]*/==> /* )]*/ (la parenthèse au début)
{()]==> () (le crochet et le crochet carré)

  • L'entrée peut être prise de la manière la plus pratique (STDIN, argument de ligne de commande, lecture à partir d'un fichier, etc.)
  • S'il existe plusieurs façons de résoudre l'inadéquation avec le même nombre de suppressions, l'une ou l'autre est acceptable.
  • Il n'y aura que des décalages entre parenthèses. Les littéraux de chaîne et les commentaires seront toujours correctement formés.
  • Le titre vient de ce fil SO
  • Il n'y aura jamais de citations dans les commentaires, de citations dans les citations, de commentaires dans les commentaires ou de commentaires dans les citations.

C'est le golf de code, donc le nombre minimum d'octets gagne. Posez des questions dans les commentaires si la spécification n'est pas claire.

Absinthe
la source
Oups, nos modifications sont en quelque sorte entrées en collision là-bas. : P Tout devrait être corrigé maintenant.
Poignée de porte
@ Doorknob Merci pour cela, au fait. Je ne savais pas comment arrêter SE d'essuyer les espaces.
absinthe
Faut-il gérer les échappements dans les chaînes de caractères (par exemple ("foo (\") bar"))?
Poignée de porte
1
Je dirais que la sortie correcte pour {{(})devrait être { } ou équivalente, car le scénario d'ouverture implique que le code fonctionnait au départ et {(})compte comme des crochets incompatibles dans tous les langages de programmation que je connais (c'est-à-dire "provoque une stase" ??). Mais alors, j'ai déjà écrit une réponse, donc je suis partiale.
DLosc
3
Je vois. Je suppose que je ne suis pas assez incompétent. ;)
DLosc

Réponses:

6

Ruby, 223 caractères

Celui-ci s'est avéré un peu long.

u,b,i=[],[[],[],[]],-1
s=gets.gsub(/(\/\*|"|').*?(\*\/|"|')|~/){|m|u+=[m];?~}
s.chars{|c|i+=1
(t='{[('.index(c))?b[t].push(i):((t='}])'.index(c))&&(b[t].pop||s[i]=' '))}
b.flatten.map{|l|s[l]=' '}
puts s.gsub(/~/){u.shift}

Ce qu'il fait est de retirer les chaînes et les commentaires en premier, afin qu'ils ne soient pas comptés (et les réintègre plus tard).

Ensuite, il parcourt la chaîne caractère par caractère. Lorsqu'il trouve une accolade ouvrante, il enregistre sa position. Lorsqu'il trouve une accolade fermante, il sort de sa matrice de stockage d'accolade ouverte respective.

Si poprenvoie nil(c'est-à-dire qu'il n'y avait pas assez d'accolades ouvrantes), il supprime l'accolade fermante. Une fois cette opération terminée, il supprime les accolades d'ouverture supplémentaires restantes (c'est-à-dire qu'il n'y avait pas assez d'accolades de fermeture).

À la fin du programme, il remet toutes les chaînes et les commentaires et les renvoie.

Non golfé:

in_str = gets

# grab strings and comments before doing the replacements
i, unparsed = 0, []
in_str.gsub!(/(\/\*|"|').*?(\*\/|"|')|\d/){|match| unparsed.push match; i += 1 }

# replaces with spaces the braces in cases where braces in places cause stasis
brace_locations = [[], [], []]
in_str.each_char.with_index do |chr, idx|
    if brace_type = '{[('.index(chr)
        brace_locations[brace_type].push idx
    elsif brace_type = '}])'.index(chr)
        if brace_locations[brace_type].length == 0
            in_str[idx] = ' '
        else
            brace_locations[brace_type].pop
        end
    end
end
brace_locations.flatten.each{|brace_location| in_str[brace_location] = ' ' }

# put the strings and comments back and print
in_str.gsub!(/\d+/){|num| unparsed[num.to_i - 1] }
puts in_str
Poignée de porte
la source
C'est vraiment impressionnant. Une question, cependant: cela fonctionnera-t-il toujours pour une entrée comme (("string"/*comment*/)"string"? Si je lis (la version non golfée) correctement, vous remplacez les chaînes et les commentaires par leur index dans le unparsedtableau, ce qui conduirait à une substitution comme ((12)3et à la recherche d'un index 12(ou 11) inexistant . Je vois que la version golfée utilise seulement shift, mais ne pourrait-elle pas encore avoir un problème similaire?
DLosc
4

Python 3, 410 322 317

import re;a='([{';z=')]}';q=[re.findall('".*?"|/\*.*?\*/|.',input())]
while q:
 t=q.pop(0);s=[];i=0
 for x in t:
  if x in a:s+=[x]
  try:x in z and 1/(a[z.find(x)]==s.pop())
  except:s=0;break
 if[]==s:print(''.join(t));break
 while 1:
  try:
   while t[i]not in a+z:i+=1
  except:break
  u=t[:];u[i]=' ';q+=[u];i+=1

Essaie tous les ensembles de suppressions possibles, en commençant par les plus petits, jusqu'à ce qu'il en trouve un où les accolades sont équilibrées. (J'entends par là parfaitement équilibré: {{(})produit ( ), non {(}).)

La première version utilisait une fonction de générateur récursif, ce qui était vraiment cool mais aussi très long. Cette version effectue une recherche simple en largeur à l'aide d'une file d'attente. (Oui, c'est un algorithme de temps factoriel. Quel est le problème?: ^ D)

DLosc
la source
J'aime celui-ci car il trouve en fait le moins de suppression et produit des expressions correctement imbriquées, mais le dernier commentaire de @vonilya suggère qu'une imbrication correcte n'est pas importante. Cependant, il est vraiment lent si de nombreux accolades doivent être retirés.
rici
2

C - 406

Une tentative en C sans utiliser d'expressions régulières.

#define A if((d==125||d==93||d==41)
char*s;t[256];f(i,m,n,p){while(s[i]!=0){int c=s[i],k=s[i+1],v=1,d;if((c==42&&k==47)||(c==m&&i>n))return i;if(!p||p==2){if((c==39||c==34)||(c==47&&k==42)){i=f(i,c*(c!=47),i,p+1);
c=c==47?42:c;}d=c+1+1*(c>50);A){v=f(i+1,d,i,2);if(!p&&v)t[d]++;if(p==2&&v)i=v;}}d=c;A&&!p){v=!!t[c];t[c]-=v;}if(p<2)putchar(c*!!v+32*!v);i++;}return 0;}main(int c,char*v[]){s=v[1];f(0,0,0,0);}

Pour compiler et exécuter (sur une machine Linux):
gcc -o brackets brackets.c
./brackets "[(])"

Dans les cas non définis comme [(]), il renvoie la dernière paire de crochets valide ()

Markuz
la source
2

Python 3, 320

import re
O=dict(zip('([{',')]}'))
def o(s,r,m=0,t=[]):m+=re.match(r'([^][)({}/"]|/(?!\*)|/\*.*?\*/|".*?")*',s[m:]).end();return r and o(s[:m]+' '+s[m+1:],r-1,m+1,t)or(o(s,r,m+1,t+[O[s[m]]])if s[m]in O else[s[m]]==t[-1:]and o(s,r,m+1,t[:-1]))if s[m:]else not t and s
s=input();i=0;a=0
while not a:a=o(s,i);i+=1
print(a)

Comme la solution de DLosc, cela étudie toutes les suppressions possibles, mais il utilise une stratégie d'exploration et de secours récursive qui est beaucoup plus rapide. Je sais que la vitesse n'est pas un critère dans le golf de code, et la recherche exhaustive est en tout cas exponentielle, mais celle-ci peut gérer des entrées comme ({({({({({({({({(}}}}}}}}en quelques secondes.

rici
la source
Bien joué, bien joué. J'ai réussi à descendre à 317, mais je pense que vous devriez pouvoir le passer assez facilement. (Pendant ce temps, mon programme
tourne toujours au ralenti
@DLosc: Ne retenez pas votre souffle :). Il a fallu 58 minutes à ma machine pour faire la version de ce modèle avec 6 parens ouverts. Afin de résoudre la stase avant que l'univers n'atteigne la mort par la chaleur, vous devrez mémoriser la file d'attente; sinon, vous vous retrouvez avec une O(n!!)solution, non O(n!). (Mon golf est O(n*2^n)au lieu de O(2^n), car il oproduit en fait tous les motifs avec des rsuppressions au lieu d'exactement des rsuppressions. Facile à réparer, mais cela coûterait quelques caractères.)
rici