Trouvez le premier match entre parenthèses

22

Ce fut l'un d'une série de défis menant à l'anniversaire de Brain-Flak. En savoir plus ici .

Défi

Pour ce défi, votre objectif sera de trouver la toute première paire de supports correspondants dans une chaîne de ()[]{}<>supports parfaitement adaptée . Pour emprunter la définition de DJMcMayhem d'une chaîne entièrement appariée:

  • Aux fins de ce défi, un « support » est l' un de ces caractères: ()[]{}<>.

  • Une paire de crochets est considérée comme "assortie" si les crochets d'ouverture et de fermeture sont dans le bon ordre et ne contiennent aucun caractère, comme

    ()
    []{}
    

    Ou si chaque sous-élément à l'intérieur est également mis en correspondance.

    [()()()()]
    {<[]>}
    (()())
    

    Les sous-éléments peuvent également être imbriqués plusieurs couches en profondeur.

    [(){<><>[()]}<>()]
    <[{((()))}]>
    
  • Une chaîne est considérée comme "entièrement mise en correspondance" si et seulement si chaque paire de supports a le support d'ouverture et de fermeture correct dans le bon ordre.

Contribution

L'entrée consistera en une seule chaîne non vide ou un tableau de caractères contenant uniquement les caractères ()[]{}<>, et il est garanti qu'elle correspond parfaitement. Vous pouvez prendre l' entrée d'une manière raisonnable qui correspond à nos valeurs par défaut i / o .

Sortie

La sortie de votre programme ou fonction sera l'index de la parenthèse qui ferme la première. Sortie doit être soit 0ou 1indexé. Encore une fois, la sortie peut être d'une manière raisonnable qui correspond à nos valeurs par défaut i / o .

Cas de test

Input       0-indexed   1-indexed
()          1           2
(<>)        3           4
<[]{<>}>    7           8
{}{}{}{}    1           2
[[]<>[]]    7           8

C'est le , le moins d'octets gagne!

Pavel
la source
3
Points bonus si vous répondez dans Brain-Flak ofc :)
Erik the Outgolfer
1
@EriktheOutgolfer Done
DJMcMayhem
1
Cette technique est très utile pour écrire des implémentations inefficaces de BF.
Esolanging Fruit

Réponses:

2

V , 4 octets

%Dø.

Essayez-le en ligne!

Contrairement à la plupart des réponses V, cela utilise l'indexation 0. Je suis extrêmement fier de cette réponse et du chemin parcouru par ma langue. Explication:

%       " Jump to the first bracket match
 D      " Delete everything under and after the cursor
  ø     " Count the number of times the following regex is matched:
   .    "   Any character
DJMcMayhem
la source
N'y a-t-il pas un passe-partout dont vous avez besoin pour faire correspondre <>?
Pavel
@ Pavel In vim, oui. Mais pas en V.
DJMcMayhem
27

Brain-Flak , 685, 155, 151 , 137 octets

(())({<{}({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>
([{}()]{})(({})){{}({}[()])(<()>)}{}(<>)<>{{}<>{}({}<>)}{}(<>[]<>)>()}<>)

Essayez-le en ligne!

136 octets de code, plus un octet pour -a. Un indexé.

530 octets au golf! C'est probablement le plus grand golf que j'ai jamais fait.

14 octets économisés grâce à Riley!

Cela abuse d'une formule de la parenthèse ouvrante / fermante: si vous prenez les valeurs ASCII, incrémentez-les d'une unité et prenez le module de 4, les ouvreurs ( ({[<) obtiendront toujours 0ou 1, tandis que les fermeteurs ( )}]>) obtiendront toujours 2 ou 3.

Explication:

#Push 1
(())

#While true
({<

    #Pop stack height
    {}

    #Compute (TOS + 1) % 4
    ({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{})

    #Decrement if positive
    (({})){{}({}[()])(<()>)}{}

    #Push 0 onto alternate
    (<>)

    #Toggle back
    <>

    #Pop two zeros from alternate if closer
    {{}<>{}({}<>)}{}

    #Push height of alternate stack
    (<>[]<>)

#Make each time through evaluate to 1
>()

#Endwhile
}

#Push the number of loops onto the offstack
<>)
DJMcMayhem
la source
8
Pour l'amour de Dieu, qu'est-ce que c'est que ça?
Leaky Nun
Fondamentalement, tout le monde utilise désormais n-1&2/ n+1&2/ -n&2ou n%7&2pour distinguer les parenthèses d'ouverture et de fermeture ...
ETHproductions
@ETHproductions Je ne sais pas si le brain-flak peut calculer efficacement &2, mais je vais l'examiner.
DJMcMayhem
Oh, je pensais que tu l'étais. Vous devez faire quelque chose de similaire pour faire la distinction entre 0/ 1et 2/ 3... bien que maintenant que je le regarde, vous décrémentez simplement si positif. Un truc sympa aussi :-)
ETHproductions
1
Le (TOS+1)%4peut être plus court: essayez-le en ligne!
MegaTom
11

05AB1E , 17 16 10 octets

-1 grâce à carusocomputing

-6 merci à Adnan pour sa perspicacité étonnante qui "après incrémentation, l'avant-dernier bit est 0 pour une parenthèse d'ouverture et 1 pour une parenthèse de fermeture"

Ç>2&<.pO0k

Essayez-le en ligne!

Ç          # Get input as ASCII values
 >         # Increment
  2&       # And with 2 (0 for open and 2 for close brackets)
    <      # decrement 
     .p    # prefixes
       O   # Sum
        0k # Print the index of the first 0
Riley
la source
žusemble utilisable ici.
Urne de poulpe magique
žu8ÝÈÏdonc, non, pas vraiment lol. Au mieux, ce sera toujours 5 octets. Je pensais plus à la division en paires d'accolades et à la suppression des accolades jusqu'à ce qu'il ne reste plus qu'une paire, incrémenter le compteur de 2 pour chaque paire supprimée. Je ne sais pas si c'est moins cependant. L'essayer atm.
Urne de poulpe magique du
Pour 10 octets: Ç>2&<.pO0k.
Adnan
1
Je déconne avec les valeurs ASCII. Notez qu'après l'incrémentation, l'avant-dernier bit est 0pour une parenthèse ouvrante et 1pour une parenthèse fermante.
Adnan
11

Vim, 23 octets

:se mps+=<:>
%DVr<C-a>C1<esc>@"

Essayez-le en ligne!

Je suis vraiment triste de cette réponse. Cette solution est magnifiquement élégante et courte, mais, par défaut, vim ne prend pas en compte <et n'est pas >compatible, j'ai donc besoin de 13 octets de code standard. Sinon, ce ne serait que de 10 octets.

J'aurais posté une réponse V, mais ce ne serait qu'un octet plus court, à savoir passer Vrà Ò, car Vrc'est un idiome vim courant.

Ceci est indexé 1 mais pourrait être modifié de manière triviale pour être indexé 0 en changeant le 1en a 0.

:se mps+=<:>        " Stupid boilerplate that tells vim to consider `<` and `>` matched
%                   " Jump to the bracket that matches the bracket under the cursor
 D                  " Delete everything from here to the end of the line
  V                 " Visually select this whole line
   r<C-a>           " Replace each character in this selection with `<C-a>`
                    " This conveniently places the cursor on the first char also
         C          " Delete this whole line into register '"', and enter insert mode
          1<esc>    " Enter a '1' and escape to normal mode
                @"  " Run the text in register '"' as if typed. Since the `<C-a>` command
                    " Will increment the number currently under the cursor
DJMcMayhem
la source
1
Postez une réponse en V alors :)
Erik the Outgolfer
10

Gelée , 11 10 9 octets

O’&2’+\i0

Essayez-le en ligne!

Explication

L'idée ici était de trouver une "formule magique" qui puisse distinguer l'ouverture des crochets de fermeture. J'ai utilisé à l'origine O%7&2(c'est-à-dire "prendre le code ASCII, modulo 7, au niveau du bit et 2"), mais @ETHproductions a suggéré O’&2(qui remplace le modulo 7 par une décrémentation); les deux renvoient 0 pour une sorte de parenthèse et 2 pour l'autre. La soustraction de 1 ( ) transformera ces résultats en -1 et 1.

Le reste du code est +\. +\produit une somme cumulée. Si un ensemble de crochets est correctement mis en correspondance, il contiendra le même nombre de -1 et de 1, c'est-à-dire que sa somme cumulée sera 0. Ensuite, nous avons juste besoin de renvoyer l'index du premier 0 dans la liste résultante; nous pouvons le faire avec i0.


la source
Fascinant comment nous avons adopté une approche similaire pour détecter les parenthèses fermantes. Malheureusement, je n'ai trouvé qu'une version inférieure:b*2%7>3
2501
Approche intéressante! J'ai développé une réponse plus longue (pour la pratique) que j'ai finalement étudiée pratiquement, sauf de manière assez intéressante, au lieu du premier décrément de votre message, j'ai eu un incrément à la place. :)
HyperNeutrino
9

Rétine , 26 24 octets

M!`^.(?<-1>([[({<])*.)*

Essayez-le en ligne!

Le résultat est basé sur 1.

Explication

Une solution Retina très différente qui est essentiellement basée sur une seule expression régulière (et très lisible ...). Cela utilise une nouvelle technique que j'ai découverte hier pour faire correspondre des chaînes équilibrées à l'aide de groupes d'équilibrage .

M!`^.(?<-1>([[({<])*.)*

Find ( M) et return ( !) toutes les correspondances de l'expression régulière ^.(?<-1>([[({<])*.)*. Cette expression régulière saute le premier caractère de la chaîne, puis utilise des groupes d'équilibrage pour garder une trace de la profondeur d'imbrication. Toute [({<augmentation de la profondeur (suivi par groupe 1) et tout autre caractère diminue la profondeur (en principe, la .permet également de diminuer la profondeur en ouvrant les crochets, mais puisque l'expression régulière est appariée avec avidité, le backtracker ne tentera jamais que ). L'astuce étrange est que le (?<-1>...)groupe entoure 1qui fonctionne parce que l'éclatement d'un groupe d'équilibrage se produit à la fin du groupe. Cela permet d'économiser deux octets sur l'approche standard sous la forme((open)|(?<-2>close))*. La correspondance s'arrête nécessairement à la parenthèse qui ferme la première, car nous l'avons ignorée, elle n'est donc pas prise en compte dans la profondeur de pile (et la profondeur de pile ne peut pas devenir négative).

La longueur de cette correspondance est l'index de base 0 du support que nous recherchons.


Comptez simplement le nombre de correspondances vides dans cette chaîne. Le regex vide correspond toujours une fois de plus qu'il n'y a de caractères dans la chaîne, donc cela nous donne l'index basé sur 1 de la parenthèse que nous recherchons.

Martin Ender
la source
C'est brillant!
Pavel
Approche plus courte : supprimez la deuxième partie de la chaîne au lieu de faire correspondre la première partie. J'aime la façon dont vous avez mesuré la longueur de la chaîne, btw!
Leo
@Leo C'est vraiment bien! Vous pouvez poster cela comme une réponse séparée :)
Martin Ender
Ok, cette nouvelle astuce pour les cordes équilibrées est merveilleuse: D
Leo
6

Rétine , 24 octets

.(([[({<])|(?<-2>.))*$


Essayez-le en ligne!

Ceci est inspiré par la solution de Martin Ender .

Explication

La première ligne est une expression régulière qui correspond à un caractère suivi d'une chaîne équilibrée allant jusqu'à la fin de la chaîne principale (pour une explication détaillée de la façon dont les groupes d'équilibrage sont utilisés dans cette expression régulière, voir la réponse de Martin). Étant donné que les expressions régulières recherchent des correspondances de gauche à droite, cela trouvera le sous-correctif correct le plus long, c'est-à-dire tout ce qui se trouve après le crochet qui ferme le premier, plus le crochet lui-même.

La ligne suivante est vide, nous remplaçons donc la correspondance par une chaîne vide, ce qui signifie que nous n'avons plus qu'à compter les caractères restants pour obtenir le résultat souhaité (indexé 0).

La dernière ligne vide compte le nombre de correspondances de la chaîne vide dans la chaîne, qui est un de plus que le nombre de caractères de la chaîne, équivalent au résultat indexé 1.

Leo
la source
J'ai trouvé hier une nouvelle technique pour faire correspondre les chaînes équilibrées qui économise deux octets sur nos deux réponses: tio.run/##K0otycxL/K@q4Z7wX0/D3kbX0E4jOlqj2iZWU0tPU0uFi@v/… (et probablement une douzaine d'autres que j'ai écrites dans le passé ...)
Martin Ender
5

Perl 5 , 28 octets

Enregistré 6 octets en utilisant juste .au lieu de [>})\]], de la réponse Retina de Martin Ender .

27 octets de code + -pindicateur.

/([<{([](?0)*.)+?/;$_=$+[0]

Essayez-le en ligne!

Regex récursif, quelle belle invention.
L'expression régulière recherche une parenthèse ouvrante ( [<{([]), suivie d' un appel récursif ( ?0), suivie d'une parenthèse fermante ( .). Tout cela de manière non-gourmande ( +?) donc il correspond le plus court possible depuis le début. L'index de la fin du match est la réponse, et en l'occurrence, il peut être trouvé dans $+[0].

Dada
la source
4

JavaScript (ES6), 55 53 52 octets

1 octet enregistré grâce à @Adnan

f=([c,...s],i=1)=>(i-=-c.charCodeAt()&2)&&1+f(s,++i)

Pour chaque parenthèse ouvrante, prendre son code de code mod 4 nous donne 0 ou 3; pour les parenthèses fermantes, il nous donne 1 ou 2. Par conséquent, nous pouvons distinguer entre parenthèses ouvrantes et fermantes en annulant le code de caractère de la parenthèse (qui retourne les bits et soustrait 1) et en prenant le deuxième bit le moins significatif; c'est-à-dire n&2,.

ETHproductions
la source
Je pense qu'au lieu de n-1&2, ça -n&2marche aussi?
Adnan
@Adnan Hmm, je pense que vous avez raison. Merci!
ETHproductions
4

C, 75 72 56 55 54 45 octets

a;f(char*s){return(a-=(-*s++&2)-1)?1+f(s):0;}

Voyez-le fonctionner en ligne .

Si vous souhaitez que la sortie soit indexée 1 au lieu de 0, remplacez la dernière 0par 1.

2501
la source
4

Python 2.7 + Numpy, 85 79 octets

Ma première tentative de code golf:

from numpy import*
lambda s:list(cumsum([(ord(x)+1&2)-1for x in s])).index(0)
acidtobi
la source
1
Bienvenue sur le site!
DJMcMayhem
1
Vous n'avez pas besoin de nommer lambdas, vous pouvez supprimer le g =
Pavel
4

Brain-Flak , 97 octets (96 pour le code, 1 pour le drapeau)

{}<>(())({<(<()>)<>({<({}[()])><>([{}]())<>}{})<>(<{}>())<>{({}[()])<>([{}])<>}{}<>({}{})>()}{})

Courez avec le -adrapeau.

Essayez-le en ligne!

Explication:

#Skip the first open bracket 
{}

#Place a 1 on stack B, representing the nesting depth
<>(())

#Start a loop, until the depth is 0
({<

 #Divide the ASCII code by 2, rounding up
 (<()>)<>({<({}[()])><>([{}]())<>}{})<>

 #Replace TOS B with a 1
 (<{}>())

 #Swap back to stack A
 <>

 #Negate the 1 on stack B n times (n = ASCII value+1/2)
 {({}[()])<>([{}])<>}{}

 #Swap back to stack B
 <>

 #Add the 1/-1 (depending on Open/close bracket) to the nesting depth accumulator
 ({}{})

 #Count loop cycles
 >()

#end loop, print result implicitly by pushing to the stack 
}{}) 

Ça marche, d'accord.

MegaTom
la source
3

Rétine , 34 octets

^.
!
T`([{}])`<<<>
+T`p`!`<!*>
\G!

Essayez-le en ligne!

Le résultat est basé sur 0.

Explication

^.
!

Remplacez le premier caractère par un !. Cela fait que le support que nous recherchons est inégalé.

T`([{}])`<<<>

Convertissez les parenthèses, les crochets et les accolades en crochets angulaires. Étant donné que la chaîne est entièrement compatible, nous ne nous soucions pas du tout des types réels, ce qui économise quelques octets à l'étape suivante.

+T`p`!`<!*>

À plusieurs reprises ( +) remplacer chaque caractère dans toutes les correspondances <!*>avec avec !s. Autrement dit, nous faisons correspondre des paires de crochets qui ne contiennent plus de crochets non traités et les transformons en points d'exclamation supplémentaires. Cela transformera la chaîne entière sauf le crochet de fermeture inégalé en points d'exclamation.

\G!

Comptez le nombre de points d'exclamation principaux, qui est égal à la position de base 0 du premier point d'exclamation (c'est-à-dire le crochet sans correspondance). Les \Gancres correspondent chacune à la précédente, c'est pourquoi cela ne compte pas les !s après ledit support.

Martin Ender
la source
J'ai vu que vous aviez répondu sur la page d'accueil et je savais qu'il allait utiliser une sorte de regex
Christopher
@Christopher Eh, celui-ci utilise à peine n'importe quel regex (contrairement à l'autre réponse Retina que je viens de poster ...).
Martin Ender
Sheesh. Regex beaucoup?
Christopher
Pourquoi ça ne marche pas?
Leaky Nun
@LeakyNun Parce que (?!(2))c'est juste (?!2). Vous vouliez probablement dire (?(2)(?!))ou (?2)!). Vous avez également oublié de vous échapper ]et la finale +doit être *.
Martin Ender
2

PHP, 116 octets

for($l=["("=>")","["=>"]","{"=>"}","<"=>">"][$f=$argn[0]];;$d>0?$i++:die("$i"))$d+=$f!=($n=$argn[$i])?$n==$l?-1:0:1;

Version en ligne

Jörg Hülsermann
la source
PHP n'a-t-il pas besoin de commencer <?php?
Pavel
@Phoenix: Il existe un interpréteur PHP autonome qui ne nécessite pas la balise de départ. C'est ce qui est normalement utilisé pour le golf.
@ ais523 Dans ce cas, PHP s'exécute à partir de la ligne de commande avec l'option -R
Jörg Hülsermann
2

Python , 76 octets

f=lambda s,r=[],i=0:(i<1or sum(r))and f(s[1:],r+[(ord(s[0])+1&2)-1],i+1)or i

Fonction récursive qui utilise l'ordinal 2nd LSB comme indicateur pour l'astuce open vs close utilisée par beaucoup trouvée par Adnan (et probablement d'autres). La queue frappe lorsque la somme cumulée de l' -1ouverture et 1de la fermeture atteint zéro. L'index est conservé dans une variable car il est moins cher que l'octet len(r), l'indexation est basée sur 1.

Essayez-le en ligne!

Jonathan Allan
la source
2

Rubis, 35 34 octets

p$_[/[<{(\[](\g<0>)*[>})\]]/].size

Basé sur la réponse Perl5 de Dada . La sortie est indexée 1. Nécessite que l'interpréteur Ruby soit invoqué avec l' -noption (implicitewhile gets boucle ).

Edit: c'est aussi 35 34 octets, mais c'est un autre point de départ possible pour réduire encore cette réponse.

p$_[/[<{(\[](\g<0>)*[>})\]]/]=~/$/

Edit2: Suppression des espaces inutiles après p.

Edit3: Quelques réponses de 34 octets supplémentaires.

~/[<{(\[](\g<0>)*[>})\]]/;p$&.size
p~/[<{(\[](\g<0>)*[>})\]]/+$&.size
Ray Hamel
la source
2
Bienvenue chez PPCG!
Pavel
1
Très appréciée! :)
Ray Hamel
2

Python 3 , 59 55 50 49 octets

f=lambda s,n=1:n and-~f(s[1:],n+1-(-ord(s[1])&2))

La sortie est indexée 0. La formule pour déterminer la direction du crochet a été découverte pour la première fois par @ETHProductions et améliorée par @Adnan.

Essayez-le en ligne!

Dennis
la source
1

Lot, 172 octets

@set/ps=
@set/ai=d=0
:l
@set/ai+=1,d-=1
@set c="%s:~,1%"
@set "s=%s:~1%
@for %%a in ("<" "(" "[" "{")do @if %%a==%c% set/ad+=2&goto l
@if %d% gtr 0 goto l
@echo %i%

1 indexé. <>s sont bien sûr des caractères spéciaux dans Batch donc non seulement je dois citer partout, mais je ne peux même pas faire d'astuces telles que les faire des gotoétiquettes.

Neil
la source
1

R, 126 octets

s=readline();i=0;r=0;for(c in strsplit(s,"")[[1]]){if(grepl("[\\[\\(\\{<]",c))i=i+1 else i=i-1;if(i==0){print(r);break};r=r+1}
Neil
la source
0

C, 127 octets

Essayez en ligne

c(x){x-40&x-60&x-91&x-123?-1:1;}
f(i,t)char*t;{return i?f(i+c(*t),t+1):t;}
s(char*t){return f(c(*t),t+1)-t;}

Sortie

2   ()
4   (<>)
8   <[]{<>}>
2   {}{}{}{}
8   [[]<>[]]
Khaled.K
la source
Tout commentaire, downvoter.
Khaled.K
Je n'étais pas le downvoter, mais je ne pense pas que cela aide qu'il y avait déjà une soumission C beaucoup plus courte.
Ørjan Johansen