Bernhard Peissl: pass-by-reference in Perl ???

Halli Hallo!

Gibts irgendsowas ähnliches wie pass by reference auch in Perl? Ich
würd gern mehrere Variablen mit einem Funktionsaufruf ändern. Also
z.B. statt:

// $susi = "susi";
// $susi = schlag($susi);
// $strolchi = "strolchi";
// $strolchi = schlag($strolchi);

// sub schlag { $_[0] =~ s/\w/_mit_dem_blauen_auge/g; return $_[0]; }

also irgendwas wie:

// $susi = "susi";
// $strolchi = "strolchi";
// schlag($susi, $strolchi);

Geht das ??? -nicht das schlagen, du scherzkeks  ;-) Ich will ja
keine Tiere quälen, brächt ich ja nie übers Herz ;-)

Liebe Grüsse
Bernhard aka RAMBO!!!!

  1. Tag Bernhard!

    Gibts irgendsowas ähnliches wie pass by reference auch in Perl?

    Klar doch, geht mit... Referenzen (na sowas *g*). Die erzeugt man in Perl mit einem \ vor der Variablen. Also
    $susi_ref = $susi;     # Eine Referenz ist selbst wiederum ein Skalar

    Dereferenzieren fuer Skalarreferenzen mit voranstellen eines weiteren $:
    $$susi_ref = "susi";

    Genaueres findest Du natuerlich in den perldocs, insbesondere perlre.

    // sub schlag { $_[0] =~ s/\w/_mit_dem_blauen_auge/g; return $_[0]; }

    also irgendwas wie:

    // $susi = "susi";
    // $strolchi = "strolchi";
    // schlag($susi, $strolchi);

    sub schlag {
        my $x;
        
        while ($x = shift()) {
            $$x =~ s/\w/_mit_dem_blauen_auge/g;
        }
    }

    So long

    1. Hallo Calocybe

      Ich habs mir das perlreftut ja durchgelesen, aber da stand irgendwie
      immer nur was von der einen Richtung, nämlich einzelne Daten aus
      einem Array/Hash auszulesen, aber nicht, dass man Referenzen auch
      dazu benützen könnte, diese zu verändern, und erst recht nicht, dass
      man sie auf stinknormale Skalare anwenden kann. Dumm wie ich nun mal
      bin, hab ich mich damit gleich abgefunden :-(

      Dereferenzieren fuer Skalarreferenzen mit voranstellen eines
      weiteren $:
      $$susi_ref = "susi";

      Also übertragen:

      int* susi = &strolchi; <=>  $susi = $strolchi;
      *susi = 6              <=> $$susi = 6;

      ... in beiden Fällen ist strolchi==6, habe ich das jetzt geschnallt??

      Genaueres findest Du natuerlich in den perldocs, insbesondere perlre.

      Da hab ich doch glatt mal was gelesen, aber wart mal, hiess das nicht
      perlre!f! ;-) perlre ist aber auch so ein Spezialgebiet von mir ;-)

      sub schlag {
          my $x;
          while ($x = shift()) {

      »»         $$x =~ s/\w/_mit_dem_blauen_auge/g;
      »»     }

      }

      Na hui hui hui!!!! da seh ich ja was, das ich noch nie gesehen habe:
      was bitte macht shift()? und wo belegst du $x mit einem Wert?

      Vermutung: while($x=shift()) weist $x der reihe nach jeden Parameter
      zu, der der Funktion übergeben wurde! Stimmts, oder hab ich Perl
      immer noch nicht kapiert?

      liebe Grüsse,
      Bernhard

      1. Hi ho!

        Ich habs mir das perlreftut ja durchgelesen, aber da stand irgendwie

        Oh, das kannte ich ja noch gar nicht. Hab immer nur perlref gelesen. *g*

        Also übertragen:

        int* susi = &strolchi; <=>  $susi = $strolchi;
        *susi = 6              <=> $$susi = 6;

        »»

        ... in beiden Fällen ist strolchi==6, habe ich das jetzt geschnallt??

        Yepp.

        Da hab ich doch glatt mal was gelesen, aber wart mal, hiess das nicht
        perlre!f! ;-) perlre ist aber auch so ein Spezialgebiet von mir ;-)

        Aeh.. ja, meinte ich. *g*  Aber perlre ist auch ne lustige Sache. ;-)

        Vermutung: while($x=shift()) weist $x der reihe nach jeden Parameter
        zu, der der Funktion übergeben wurde! Stimmts, oder hab ich Perl
        immer noch nicht kapiert?

        Ja. Genaugenommen entfernt shift() das erste Element eines Arrays und gibt es zurueck. Wenn man nicht sagt, *welches* Array gemeint ist, wird @_ bearbeitet. Wenn nichts mehr uebrig ist vom Array, ergibt das undef und das while wird abgebrochen.

        Den Hinweis von Kai kannte ich auch noch nicht. Damit kann man das auch so schreiben:

        sub schlag {
            for (@_) {
                s/\w/_mit_dem_blauen_auge/g;
            }
        }

        und dann aber keine Referenzen mehr uebergeben, sondern die Skalare direkt.

        So long

        1. Hallo Calocybe

          Ich habs mir das perlreftut ja durchgelesen, aber da stand irgendwie
          Oh, das kannte ich ja noch gar nicht. Hab immer nur perlref gelesen. *g*

          Ja das gibts, ist ein bissl weniger hardcore als perlref. Ideal für mich ;-)

          sub schlag {
              for (@_) {
                  s/\w/_mit_dem_blauen_auge/g;
              }
          }

          Also, was da alles geht. Wenn man das einem Informatiker vorlegt, schlagt der wahrscheinlich alle Hände üner dem Kopf zusammen ;-)

          Ich würde mir gerne erlauben, mit dem Thema einwenig abzuschweifen. Ich weiss dass es schon ziemlich ausgelutscht ist, daher will ich auch keinen neuen Thread anfangen, aber ich werkel da jetzt schon 2 Tage lang herum, und es wird einfach nix.

          Ich habe gefragt, ob pass-by-reference möglich ist, um Formular-texte zu bearbeiten. Unter anderem will ich aus allen Eingaben die \n's durch <br>'s ersetzen. Nun hab ich da im Forum Unmengen zu diesem Thema gefunden.

          Hier mal, was ich alles schon probiert habe:
          // $param =~ s/\cM\n/<br>/g; # von Matt Wright oder so, geht aber auch nicht!
          // $param =~ s/\n/<br>/g;   # habe ich als allererstes probiert -Fehlanzeige
          // $param =~ s/(\015\012\012\015\015\012)/\n/g; $param =~ s/\n\n/<br>/g; # cheatahs version

          Irgendwie glaube ich nämlich er will mich verarschen. schreiben ich: $param =~ s/\n/br>/g; dann ersetzt er jede Zeilenschaltung durch br>, aber wenn ich dann das '<' noch dazugebe, dann macht er gar nix, im Quelltext steht dann einfach ein \n(Zeilenschaltung), wo eigentlich das <br> stehen sollte. Das \n kennt er jedenfalls.

          Ich bin gerade am auszucken !!!

          liebe grüsse
          Bernhard

          1. Also, was da alles geht. Wenn man das einem Informatiker vorlegt, schlagt der wahrscheinlich alle Hände üner dem Kopf zusammen ;-)

            Ach ja, diese Warmduscher... ;-)

            Hier mal, was ich alles schon probiert habe:
            // $param =~ s/\cM\n/<br>/g; # von Matt Wright oder so, geht aber auch nicht!

            In Perl gibt es immer viele Wege, ein Problem zu loesen. Manche sind sauberer, andere weniger sauber, und bei manchen Moeglichkeiten ist es eher Gluecksache, wenn sie funktionieren. Wenn Du die schlechteste dieser Moeglichkeiten suchst, dann solltest Du in Matt-Wright-Scripts nachschauen, ansonsten aber besser nicht.

            // $param =~ s/(\015\012\012\015\015\012)/\n/g; $param =~ s/\n\n/<br>/g; # cheatahs version

            Leider werden vom Schwanzabschneider dieses Forums Pipe-Zeichen (|) einfach weggeschmissen, deshalb stimmt das so nicht, wie es da steht. Eigentlich stimmt es auch nach Ergaenzung der Pipes nicht ganz. Ist das wirklich von Cheatah? Meines Wissens haben wir nach langen Diskussionen zu dieser Variante gefunden:

            Alle Zeilenumbrueche, egal wie codiert (unterscheidet sich zwischen DOS, Mac und Unix),

            in \n umwandeln (wobei der echte Wert von \n vom Server-Betriebssystem abhaengt)

            $param =~ s/\015\012|\015|\012/\n/g;

            falls noetig, alle \n in HTML-Zeilenumbrueche umwandeln

            $param =~ s/\n/<br>/g;

            Irgendwie glaube ich nämlich er will mich verarschen. schreiben ich: $param =~ s/\n/br>/g; dann ersetzt er jede Zeilenschaltung durch br>, aber wenn ich dann das '<' noch dazugebe, dann macht er gar nix, im Quelltext steht dann einfach ein \n(Zeilenschaltung), wo eigentlich das

            Kann ich nicht nachvollziehen. Aber ein Tip: Das \ vor < und > kannst Du weglassen, da diese Zeichen keine Sonderbedeutung in regulaeren Ausdruecken haben. Ist aber auch nicht falsch.

            HTH && So long

            1. Hallo Calocybe,

              Leider werden vom Schwanzabschneider dieses Forums Pipe-Zeichen () einfach weggeschmissen, deshalb stimmt das so nicht, wie es da steht. Eigentlich stimmt es auch nach Ergaenzung der Pipes nicht ganz. Ist das wirklich von Cheatah? Meines Wissens haben wir nach langen Diskussionen zu dieser Variante gefunden:

              Und nachdem ich mir den von Stefan M. geposteten Auszug aus dem Archivindex angesehen habe, glaube ich zu wissen wieso ;-). Im Index wird als Feldtrennzeichen verwendet. Da aber Pipes in diversen Programmiersprachen durchaus wichtige Zeichen sein können, könnte man doch dem "Schwanzabschneider" beibringen, diese, statt sie zu löschen, durch | zu ersetzen.
              Ich nehme auch hiermit die Initiativstrafe entgegen, dieses einzubauen, wenn man mir den "Schwanzabschneider" zukommen läßt.

              Gruß AlexBausW

              1. Nochmal mich,

                Beim Absenden habe ich dann gesehen, daß ich zu lang zitiert habe, weil die Zeilen im <textarea> des Postings (Antwort) nicht umgebrochen werden (wohl aber in "Neue Nachricht verfassen").
                Vielleicht kann ja jemand, wo er grad dabei ist ;-) auch für die <textarea> zum Antworten "wrap=virtual" einfügen, damit wir NNs auch wieder den Überblick behalten können ;-).
                [x] Ja, ich weis, daß darüber schon diskutiert wurde, und das "wrap" nicht durch den Vallidator geht {nachgeschaut habe ich nicht aber es steht zumindest so im Archiv} *g*

                Gruß AlexBausW

                P.S.: Das war der definitiv (wahrscheinlich ;-) letzte Vorschlag zu einer Änderung *g*

                1. Tag Alex!

                  Und nachdem ich mir den von Stefan M. geposteten Auszug aus dem Archivindex angesehen habe, glaube ich zu wissen wieso ;-). Im Index wird als Feldtrennzeichen verwendet.

                  Ja, das ist tatsaechlich der Grund. Allerdings koennte man die, statt ganz wegzuwerfen, einfach durch &#124; ersetzen, was wiederum der Browser am Ende als darstellt. Das waere tatsaechlich nur eine minimale Aenderung an einer bereits bestehenden Zeile im Script.

                  Vielleicht kann ja jemand, wo er grad dabei ist ;-) auch für die <textarea> zum Antworten "wrap=virtual" einfügen, damit wir NNs auch wieder den Überblick behalten können ;-).

                  Waere gut, ja.

                  [x] Ja, ich weis, daß darüber schon diskutiert wurde, und das "wrap" nicht durch den Vallidator geht {nachgeschaut habe ich nicht aber es steht zumindest so im Archiv} *g*

                  Naja, damals hatte Stefan die endgueltige Entscheidung auf "nach einem bestimmten Themenchat zum Validator" verlegt. Aber dann hat man nie wieder was davon gehoert.

                  So long

                  1. hi ho

                    [...] und das "wrap" nicht durch den Vallidator geht [...]

                    *g* <ul><ul></ul></ul> tut es aber auch nicht - daher waere es doch egal, oder?

                    cua

                    n.d.p.

            2. Hi!

              Ach ja, diese Warmduscher... ;-)

              Ha hallo!! Würd gern wissen, wie Informatiker über Perl-Programmierer denken ;-)

              In Perl gibt es immer viele Wege, ein Problem zu loesen. Manche sind sauberer, andere weniger sauber, und bei manchen Moeglichkeiten ist es eher Gluecksache, wenn sie funktionieren. Wenn Du die schlechteste dieser Moeglichkeiten suchst, dann solltest Du in Matt-Wright-Scripts nachschauen, ansonsten aber besser nicht.

              Bisher hab ich ja nicht gewusst, wer dieser Matt ist, habe aber schon desöfteren seinen Neman hier aufgeschnappt!

              Alle Zeilenumbrueche, egal wie codiert (unterscheidet sich zwischen DOS, Mac und Unix),

              in \n umwandeln (wobei der echte Wert von \n vom Server-Betriebssystem abhaengt)

              $param =~ s/\015\012\015\012/\n/g;

              falls noetig, alle \n in HTML-Zeilenumbrueche umwandeln

              $param =~ s/\n/<br>/g;

              Vielleicht geht das ja sogar fast überall, und nur ich bin das "fast". Bei mir gehts jedenfalls auch so nicht :-(
              Statt einen <br> in den Source-Code zu schreiben entfernt deine Variante alle whitespaces (also auch \n) und schreibt alles in eine Wurscht (Zeile) ins HTML-Document !!

              Kann es sein, dass <br> beim hinausschreiben auf plain/text irgendwie auch als \n interpretiert wird? Hier ist übrigens gerade dasselbe passiert. In der Antwort-textarea hier steht folgendes:

              $param =~ s/\n/
              /g;

              Ich hab da nix gedreht, das stand schon so da!! klingt irgendwie nach dem gleichen Problem nur in die andere Richtung.

              Ach, es ist alles so verwirrend ?:-(

              Wenn ich dich noch um einen Gefallen anschnorren dürfte! Könntest du bitte mal folgendes Script auf deinem Rechner ausprobieren und mir sagen, obs bei dir funktioniert?:

              use CGI;
              $obj = new CGI;

              $tester = $obj->param("testfeld");

              text2html($tester);

              print "Content-type: text/html\n\n";
              print "<html><head><title>test</title></head><body>";
              print $tester;
              print "</body></html>";

              sub text2html {
                  $laenge = @_;
                  for ($i=0; $i<$laenge; $i++) {  
                      $_[$i] =~ s/\015\012\015\012/\n/g;
                      $_[$i] =~ s/\n/<br>/g; # jaja, is schon im Einsatz :-)
              }

              und im html-file:

              <html>
              <head>
              <title>test</title>
              </head>
              <body>
              <form action="/cgi-bin/test.pl" method="GET">
              <textarea name="testfeld" cols="60" rows="10"></textarea>
              <p><input type="Submit" value="ok"></p>
              </form>
              </body>
              </html>

              Falls es bei dir funktionieren sollte, schmeiss ich meinen Computer weg, denn der macht dann anscheinend eh nur was _er_ will. Ich hatte ja schonmal so ein Spezialproblem, das bisher anscheinend nur auf meinem Computer auftauchte, kannst du dich noch erinnern?:

              <../../sfarchiv/2000_3/t16596.htm#a83777>

              Danke nochmal
              Bernhard

              1. Hi!

                Nicht mehr ausprobieren, hab den Fehler schon gefunden!!

                _Nach_ dem

                // $_[$i] =~ s/\015\012\015\012/\n/g;
                // $_[$i] =~ s/\n/<br>/g;

                hab ich noch ein

                // $_[$i] =~ s/<\w*>//g;    # start-Tags
                // $_[$i] =~ s/</\w*>//g;  # end-Tags

                stehen gehabt, das alle html-Tags aus dem Testfeld rausfiltern soll. Ob der regulärte Ausdruck stimmt weiss ich nicht. Denn mit \w sind je keine Zahlen oder Sonderzeichen wie "" dabei. Da muss ich mir noch was anderes ausdenken. Jedenfalls hat zweiteres ersteres gleich wieder gelöscht nachdem es reingeschrieben wurde.

                Ach, manchmal liegt die Lösung so nahe :-(

                Ausserdem hat eine geschwungene Klammer für die for-schleife gefehlt ;-)

                Es ist mir jetzt auch klar geworden, warum im Antwortfeld kein <br> steht, sondern eine Zeilenschaltung. Wenn ich an einem Problem so verbissen knabbere, dann scheint sich bei mir der Hausverstand immer zu verabschieden !

                Ich muss irgendwie cooler werden, gibts da irgendein perldoc perlcool oder so wo einem ausführlich und verständlich ;-) erklärt wird, wie man beim Programmieren mit Perl immer einen kühlen Kopf bewahrt ;-)

                Vielen Dank für deine Mühen,
                Bernhard

  2. Hallo Bernhard,

    Gibts irgendsowas ähnliches wie pass by reference auch in Perl? Ich
    würd gern mehrere Variablen mit einem Funktionsaufruf ändern. Also

    In Perl werden Variable standardmaessig by reference uebergeben.
    Erst mit einer lokalen Kopie von @_ aenderst Du dies in pass by value.
    Wenn Du aber @_ direkt bearbeitest, aenderst Du auch die uebergebenen Werte:

    #!perl -w
    use strict;

    my $x = 1;
    my $y = 2;

    change($x,$y);

    print "$x, $y";   # gibt 3, 4 aus

    sub change {
      
       $_[0] = 3;
       $_[1] = 4;
        
    }

    oder Du gibst einfach mehrere geaenderte Werte zurueck:

    #!perl -w
    use strict;

    my $x = 1;
    my $y = 2;

    ($x, $y) = change($x,$y);

    print "$x, $y";

    sub change {  
      
       my ($a, $b) = @_;
       $a = 3;
       $b = 4;
       return ($a, $b);

    }

    perldoc perlsub
    Oder Du benutzt Referenzen, s. Calocybe.

    Liebe Grüsse
    Bernhard aka RAMBO!!!!

    Gruss
       Kai

    1. Hallo Kai

      In Perl werden Variable standardmaessig by reference uebergeben.
      Erst mit einer lokalen Kopie von @_ aenderst Du dies in pass by value.
      Wenn Du aber @_ direkt bearbeitest, aenderst Du auch die uebergebenen Werte:

      Also man lernt ja echt nie aus! ... Das hört sich an als wär ich schon ein alter (Perl-)Hase oder? Naja, eigentlich kenn ich Perl ja noch nicht so lange, aber ich hab in diesem Formum schon ein Paar tolle Sachen gelernt, die man mit Perl anstellen kann. Das hier gehört auch dazu. Anfangs hab ich mich mit den komischen $_ ja nicht so recht anfreunden können, aber sie werden mir immer sympatischer.

      Bin schon gespannt, was ich noch alles aufschnappe hier :-)

      sub change {  
         my ($a, $b) = @_;
         $a = 3;
         $b = 4;
         return ($a, $b);
      }

      dass man Felder zurückgeben kann ist mir bekannt, aber mehrere einzelne Variablen, naja, was soll ich gross sagen, ich hab wiedermal nicht in Perl gedacht ;-)

      Liebe Grüsse
      Bernhard