2012-04-07 12 views
0

Ich versuche einen standardmäßigen RESTful URI mit regulären Ausdrücken in Ruby zu zerlegen.Rekursive Named Captures: Parsing eines RESTful URI

Angenommen, wir arbeiten an einer Musik-Diskographie-Webanwendung. Wir haben viele Künstler, die viele Alben haben, die viele Lieder haben.

Mit dieser Einrichtung alle folgenden RESTful URIs sollten als GET-Anfragen zur Verfügung:

/artists 
/artists/1 
/artists/1/albums 
/artists/1/albums/1 
/artists/1/albums/1/songs 
/artists/1/albums/1/songs/1 
/artists/1/albums/1/songs/1/artists 
/artists/1/albums/1/songs/1/artists/1 

In einem Versuch, diese URIs mit Regexp zu erfassen, ich folgendes (live example) peitschte:

^\/(?<resource>(?:artists|albums|songs))(?:\/(?<id>\d+))?\/?$ 

Wenn eine root-Ebene-Ressource, wie nachfolgend angegeben, die regexp arbeitet wie erwartet:

/artists 
/songs/1 

Die ersten resultierenden Matchdata haben eine Ressource von artists und eine ID von nil und die zweite hat eine Ressource von songs und eine ID von 1.

Wenn jedoch ein URI angegeben wird, der Zuordnungen einer Ressource anfordert, wie /albums/1/songs/1, schlägt diese Regexp fehl, weil Rekursion nicht berücksichtigt wird. Also warf ich das Ganze in einer nicht-einfangende Gruppe mit ein ‚ein oder mehr‘ (+) Qualifier darauf:

^(?:\/(?<resource>artists|albums|songs)(?:\/(?<identifier>\d+))?)+\/?$ 

Diese regexp funktioniert jetzt auch auf URIs wie /albums/1/songs/2 aber die resultierende Match enthält nur die letzte Ressource (songs) und ID (2).
Ich erwartete ein Array mit zwei Objekten, eines mit einer Ressource von albums und eines mit einer Ressource von songs.

Gibt es eine Möglichkeit, benannte Captures innerhalb einer Erfassungsgruppe korrekt zu verwenden, die den "einen oder mehrere" Qualifier verwendet?

+0

Einige Leute, wenn sie mit einem Problem konfrontiert sind, denken "Ich weiß, ich werde reguläre Ausdrücke verwenden.". Jetzt haben sie zwei Probleme. –

+4

* Und einige Leute denken, wenn sie mit regulären Ausdrücken konfrontiert werden: "Ich weiß, ich werde ein einprägsames Zitat verwenden, an das ich mich erinnere". Jetzt haben sie nichts zur Diskussion hinzugefügt. * - Tomalak –

+0

* Auf jeden Fall ist das nur meine Bauchreaktion auf Leute, die Regexes missbrauchen. * - MÄDCHEN. –

Antwort

0

Die meisten Regex-Aromen funktionieren nicht so. Jede einfangende Gruppe enthält nur die letzte Teilzeichenfolge, der sie entsprach. Es sei denn, Sie verwenden .NET regex lib, die jede Übereinstimmung der einfangenden Gruppen speichert.

0

"Rekursion" ist nicht wirklich das richtige Wort für das Problem, das Sie haben. Sie versuchen, über mehrere /resource/id Paare in Ihrer Regex zu iterieren und anschließend die einzelnen Captures abzurufen. Ich schlage vor, Sie diese Regex verwenden statt:

\/(?<resource>artists|albums|songs)(?:\/(?<identifier>\d+))? 

... und iterieren die /resource/id Paare in Ihrem Code (zum Beispiel mit der scan Methode).

+0

Problem damit ist zB '/ song/1foo/bar' wird trotzdem passen. Daher ist ein Vorvalidierungsschritt erforderlich, oder Sie verwenden '\ G' und stellen sicher, dass die Übereinstimmungsposition nach allen Übereinstimmungen dort ist, wo Sie sie haben möchten. – Qtax