[ruby-de] String-Bearbeitung, gsub

Norbert Melzer timmelzer at gmail.com
Mi Aug 30 22:20:42 JST 2017


Wolfgang Nádasi-Donner <ruby at wonado.de> schrieb am Mi., 30. Aug. 2017 um
14:32 Uhr:

> Am 30.08.2017 um 12:29 schrieb Norbert Melzer:
> > Wolfgang Nádasi-Donner <ruby at wonado.de> schrieb am Mi., 30. Aug. 2017 um
> > 12:08 Uhr:
> >
> >> Am 30.08.2017 um 02:04 schrieb Die Optimisten:
> >>> Hallo
> >>>
> >>> "ab/cd".gsub( /\/(.)/,  "\\1".upcase)        # => "Abcd"
> >>> # auf das wesentliche komprimiert
> >>> Warum wird das .upcase nicht ausgeführt?, wie tut man das (gehts auch
> >>> ohne Block)?
> >>>
> >>> danke
> >>> Andreas
> >>>
> >>>
> >>
> >> btw: Du meintest wohl "abCd" als erwartetes Ergebnis
> >>
> >
> > Wo siehst du ein erwartetes Ergebnis? Ich sehe per Konvention lediglich
> > einen Marker für „das hab ich bekommen“ und das stimmt nicht einma, denn
> er
> > bekommt lediglich `"abcd"` zurück.
> Ich verstehe Deine Antwort nicht. Die "gsub"-Methode auf den String
> "ab/cd" angewandt zieht auf dem Pattern "\/(.)" und liefert als erste
> (und einzige Gruppe) das "c". Das lässt sich in "irb" leicht nachprüfen...
>

`gsub` substituirt den Match im String durch das zweite Argument, bzw durch
was auch immer aus einem Block zurückkommt. Rückgabewert ist ein neuer
String.

Per Konvention liest man die Angabe `foo.bar() #=> 1` als „Ich habe auf die
Variable `foo` die Methode `#bar` aufgerufen und `1` als Rückgabewert
erhalten“.

Also lese ich seine Angabe so, als hätte er auf den gezeigten Aufruf den
String `"Abcd"` zurückerhalten, was aber so nicht ganz sein kann, es sei
den er zeigt weiteren wichtigen Code nicht. Bei mir kommt bei der Zeile ein
`"abcd"` zurück, das entspricht dem was ich erwarte.


> irb(main):001:0> "ab/cd".match(/\/(.)/)
> => #<MatchData "/c" 1:"c">
>

Jupp, sehe ich auch so.


> Ich hätte also erwartet, dass "gsub" mit zwei Parametern ausgeführt die
> Referenz auf die erkannte Gruppe einsetzt, dass also in dem Fall aus
> "\\1" oder '\1' das "c" in den als zweiten Parameter angegebenen String
> eingesetzt wird,


Ja, ist doch auch so.


> bevor der zur weiteren Verarbeitung (in diesem Fall
> durch "upcase") breitgestellt wird. Das scheint aber, wie die Ausgabe...
>

Nein, denn du rufst ja `#upcase` auf `'\1'` auf und nicht auf `'c'`.

Der vom OP gezeigte Einzeiler ist equivalent (oder doch eher äquivalent?)
zu folgendem Mehrzeiler:

x_1 = "\\1".upcase
"ab/cd".gsub( /\/(.)/, x_1)

In Haskell wohl ganz grob zu folgendem zu übersetzen (unter der Annahme es
gäbe entsprechend gleichnamige Funktionen):

gsub "ab/cd" "/(.)" $ upcase "\\1"


> irb(main):002:0> "ab/cd".gsub( /\/(.)/,  '\1otto\1'.upcase)
> => "abcOTTOcd"
>
>

> ...zeigt, nicht der Fall zu sein.
>

Wie gesagt, ausführungsreihenfolge beachten! Sämtliche Argumente in Ruby
müssen vollständig evaluiert sein. Ein Umstand der im übrigen für nahezu
alle Sprachen gilt.

Ich habe noch einmal in der 1.9&2.0-er Pickaxe gesucht, aber keine
> Erklärung für diesen Effekt gefunden.
>

Weil es da nicht wirklich etwas zu erklären gibt. Der Effekt ist
keinesfalls Merkwürdig, sondern leicht zu erklären und auch leicht
verständlich.


> Ich werde mich allerdings auch nicht weiter um die Sache kümmern, weil
> ich aktuell mit Haskell arbeite und Ruby ziemlich weit hinten in meine
> Prioritätsschublade gepackt ist.


Kleiner Tipp eines anderen Polygloten… Versuche die Sprachen gleichzeitig
zu verwenden. Hast du dich in Haskell erst einmal an zu viele Dinge gewöhnt
ist der Weg zurück ähnlich schwer wie der Weg nach Haskell hinein. Ich
wurde zu diesem Sprachspagat gezwungen weil wir im Studium neben Haskell
auch noch aktiv an Pascal Übungen teilnehmen mussten.


> Eine Anmerkung bezüglich dieses
> unerwarteten Effekts habe ich aber in die PickAxe geschrieben.
>

Um ehrlich zu sein glaube ich aus oben genannten Gründen nicht dass es
aufgenommen wird, ich würde mich aber auch freuen wenn du uns diesbezüglich
auf dem Laufenden hälst.


> Viele Grüsse, WoNáDo
>

Bye!
  Norbert


Mehr Informationen über die Mailingliste ruby-de