Kirjoittaja Aihe: Python/Perl ja sääntöilmaukset...  (Luettu 3351 kertaa)

SuperOscar

  • Käyttäjä
  • Viestejä: 4000
  • Ocatarinetabellatsumtsum!
    • Profiili
    • Legisign.org
Python/Perl ja sääntöilmaukset...
« : 15.06.07 - klo:09.30 »
Olen kyllä vannoutunut Pythonin suosija enkä Perliin mielelläni kajoa, mutta... Sain eilen lopulta ratkaistuksi pitkään kiusanneen ongelman, joka osoitti, kuinka vahvaa Perlin sääntölausekkeiden käsittely on. Olkoon siis opiksi ja ojennukseksi kaikille!

Tavoitteena oli muuttaa URLeissa olevia kyselylausekkeita tekstiksi. Kyselylausekkeissa mm. ääkköset oli merkitty muotoon % + heksaluku, siis esim. ä = %e4.

Perlillä homma menee näin:

Koodia: [Valitse]
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

Ts. etsitään %heksaluku-jonot, joista itse heksaluku merkitään ryhmäksi suluin, ja sitten muutetaan luku vastaavaksi merkiksi. Taikatempun tekee s-operaattorin e-valitsin, jonka ansiosta korvaava merkkijono voi olla suoritettava lauseke.

Pythonilla homma ei mene kuten seuraavassa esimerkissä, koska re.sub-funktion toisen argumentin on oltava literaali merkkijono – jos merkkijonoa yrittää jatkokäsitellä funktiossa, \n-viittaukset menettävät ”taikansa":

Koodia: [Valitse]
value = re.sub(r'%([A-Fa-f0-9][A-Fa-f0-9])', chr(int('\1', 16)), value)

Mutta tokihan myös re.subissa on taikakonsti: jos kakkosargumenttina on funktio (ei siis kutsu vaan viittaus), sitä funktiota kutsutaan suorittamaan muunnos; ja toki funktiona voi olla myös lambda, kuten tässä:

Koodia: [Valitse]
value = re.sub(r'%([A-Fa-f0-9][A-Fa-f0-9])', lambda m: chr(int(m.group(1), 16)), value)

Hoituuhan tuo siis Pythonillakin, mutta kyllä on myönnettävä sääntölausekkeiden käsittelyn olevan koko lailla vaivattomampaa Perlissä – niin ällö kieli kuin muuten onkin :)
« Viimeksi muokattu: 15.06.07 - klo:09.33 kirjoittanut SuperOscar »
pöytäkone 1, kannettavat 1–3: Debian GNU/Linux 12; pöytäkone 2: openSUSE Tumbleweed; NUC: openSUSE Leap 15.5; RPi 1: FreeBSD 14-RELEASE; RPi 2: LibreELEC 11

mgronber

  • Käyttäjä
  • Viestejä: 1458
    • Profiili
Vs: Python/Perl ja sääntöilmaukset...
« Vastaus #1 : 15.06.07 - klo:11.51 »
Tällaisten pienten koodipätkien toteutus on (ainakin minusta) mukava nähdä eri kielillä.

En ole Rubyllä vähään aikaan kirjoittanut yhtään mitään mutta pienen arpomisen jälkeen sain aikaan tämän
Koodia: [Valitse]
value.gsub!(/%([a-fA-F0-9]{2})/) { [$1.hex].pack("C") }

Edit: Enemmän tai vähemmän sama toteutettuna Tcl:n avulla:
Koodia: [Valitse]
set value [subst [regsub -all {%([a-fA-F0-9]{2})} $value {[format %c [scan \1 %x]]}]]

# Tuo tosin on yhdellä rivillä ilmaistuna turhan kaoottinen joten
# pieni uudelleenmuotoilu lienee paikallaan...
set value [subst [regsub -all \
        {%([a-fA-F0-9]{2})} \
        $value \
        {[format %c [scan \1 %x]]} \
        ]]

# Tietysti jos tuota joutuu käyttämään paljon niin siitä voi tehdä
# hieman siistimmän version tekemällä uuden funktion.

proc gsub {exp string subSpec {varName ""}} {
    if { $varName == "" } {
        uplevel [list return [subst [regsub -all $exp $string $subSpec]]]
    } else {
        uplevel [list set $varName [subst [regsub -all $exp $string $subSpec]]]
    }
}

# Nyt tuo sama asia saadaan tehtyä tällä komennolla
gsub {%([a-fA-F0-9]{2})} $value {[format %c [scan \1 %x]]} value

« Viimeksi muokattu: 15.06.07 - klo:14.44 kirjoittanut mgronber »

SuperOscar

  • Käyttäjä
  • Viestejä: 4000
  • Ocatarinetabellatsumtsum!
    • Profiili
    • Legisign.org
Vs: Python/Perl ja sääntöilmaukset...
« Vastaus #2 : 15.06.07 - klo:14.36 »
Tällaisten pienten koodipätkien toteutus on (ainakin minusta) mukava nähdä eri kielillä.

Heh, niin minustakin.

Ilmeisesti siis Rubyssakin on parempi sääntölausekkeitten käsittely kuin Pythonissa :(

Toisaalta Ruby on syntaksiltaan paljon Perliä miellyttävämpää, joten ties vaikka kääntyisin vielä sen kannalle...
« Viimeksi muokattu: 15.06.07 - klo:14.39 kirjoittanut SuperOscar »
pöytäkone 1, kannettavat 1–3: Debian GNU/Linux 12; pöytäkone 2: openSUSE Tumbleweed; NUC: openSUSE Leap 15.5; RPi 1: FreeBSD 14-RELEASE; RPi 2: LibreELEC 11

mgronber

  • Käyttäjä
  • Viestejä: 1458
    • Profiili
Vs: Python/Perl ja sääntöilmaukset...
« Vastaus #3 : 15.06.07 - klo:15.04 »
Heh, niin minustakin.

Tuolla on virheitä Tcl-koodissa. Ei toimi ainakaan 8.4-sarjalla ja epäilen että toimii millään vanhemmallakaan.

Lisäksi 4DOS kuuluisi minun mielestäni ensimmäiseksi.

Lainaus
Ilmeisesti siis Rubyssakin on parempi sääntölausekkeitten käsittely kuin Pythonissa :(

Missä kielessä ei ole? ;)

Aikoinaan kokeilin Rubya nimenomaan sen takia että siinä oli hyvin samantapainen säännönmukaisten lausekkeiden käyttötapa kuin mitä Perlissä on.

Lainaus
Toisaalta Ruby on syntaksiltaan paljon Perliä miellyttävämpää, joten ties vaikka kääntyisin vielä sen kannalle...

Ainakin Ruby on kohtuullisen selkeää ja helppolukuista. En ole pariin vuoteen sitä käyttänyt joten minulla ei ole mitään käsitystä sen uusista ominaisuuksista (ja vanhoistakin on varmaan suurin osa jo unohtunut).

SuperOscar

  • Käyttäjä
  • Viestejä: 4000
  • Ocatarinetabellatsumtsum!
    • Profiili
    • Legisign.org
Vs: Python/Perl ja sääntöilmaukset...
« Vastaus #4 : 15.06.07 - klo:15.09 »
Tuolla on virheitä Tcl-koodissa. Ei toimi ainakaan 8.4-sarjalla ja epäilen että toimii millään vanhemmallakaan.

Voi olla... Kuten sanottu, kaikkia en ole päässyt testaamaankaan. Tosin minulla on muistikuva, että Tcl-härpäkkeeni olisi tullut testatuksi.

Lainaus
Lainaus käyttäjältä: SuperOscar
Ilmeisesti siis Rubyssakin on parempi sääntölausekkeitten käsittely kuin Pythonissa :(

Missä kielessä ei ole? ;)

Niinpä :(  Mikä on kiusallista, koska Python on muuten minun käyttööni täydellinen kieli.
« Viimeksi muokattu: 15.06.07 - klo:15.11 kirjoittanut SuperOscar »
pöytäkone 1, kannettavat 1–3: Debian GNU/Linux 12; pöytäkone 2: openSUSE Tumbleweed; NUC: openSUSE Leap 15.5; RPi 1: FreeBSD 14-RELEASE; RPi 2: LibreELEC 11

mgronber

  • Käyttäjä
  • Viestejä: 1458
    • Profiili
Vs: Python/Perl ja sääntöilmaukset...
« Vastaus #5 : 15.06.07 - klo:15.25 »
Tuolla on virheitä Tcl-koodissa. Ei toimi ainakaan 8.4-sarjalla ja epäilen että toimii millään vanhemmallakaan.

Voi olla... Kuten sanottu, kaikkia en ole päässyt testaamaankaan. Tosin minulla on muistikuva, että Tcl-härpäkkeeni olisi tullut testatuksi.

Ainakin gets $figure tulisi olla muodossa gets stdin figure. Voi tietysti olla että jossakin vanhassa versiossa ei tuolle gets-funktiolle määritelty käytettävää kanavaa mutta en silti usko että $figure olisi toiminut vaan uskoisin että sen on aina pitänyt olla figure.

Vastaava ongelma on lopussa sillä puts olettaa saavansa tuossa ensiksi kanavaparametrin ja vasta sitten tekstiparametrin. Toimiva muoto olisi esimerkiksi puts "Average = $average".

Mitä muuten tulee tuon toteutukseen niin itse olisin varmaan kerännyt arvot listaan, yhdistänyt listan plus-merkeillä ja suorittanut keskiarvolaskun yhdellä expr-kutsulla. Joku kieltä oikeasti osaava tekisi sen varmaan vieläkin tyylikkäämmin.

SuperOscar

  • Käyttäjä
  • Viestejä: 4000
  • Ocatarinetabellatsumtsum!
    • Profiili
    • Legisign.org
Vs: Python/Perl ja sääntöilmaukset...
« Vastaus #6 : 15.06.07 - klo:17.56 »
Mitä muuten tulee tuon toteutukseen niin itse olisin varmaan kerännyt arvot listaan, yhdistänyt listan plus-merkeillä ja suorittanut keskiarvolaskun yhdellä expr-kutsulla. Joku kieltä oikeasti osaava tekisi sen varmaan vieläkin tyylikkäämmin.

Tuo on hyvä pointti: noinhan minäkin toteutin jutun Lispissä. Uutta kieltä kokeillessa pitäisi aina opetella myös kielen ”filosofia”, jottei väännä koodia väen väkisin jonkin toisesta kielestä varastetun mallin mukaan.

Keskiarvoprojektin sisarprojektin, lottorivin arvonnan, taustalla on muuten hauska tarina. Yksi ystäväni suoritti Java-kurssia ja halusi rakentaa itselleen lottorivin arpovan ohjelman ihan tositarpeeseen.

Lopulta hänen Java-taitonsa eivät hankkeeseen riittäneet, joten hän käytti jotain Basiciä – ja siinäkin algoritmi oli aika erikoinen. Hän tarvitsi nimittäin jokaista arvottua lukua varten uuden muuttujan, siis yhteensä seitsemän muuttujaa, ja jokaisen arvonnan jälkeen piti if-lauseella tarkistaa, ettei yksikään jo käytetyistä muuttujista sisältänyt vasta-arvottua lukua. Viimeinen if-lauseista olikin sitten aika pitkä ja kömpelö :)

Oma projektini lähti liikkeelle siitä, että yritin näyttää hänelle vähän älykkäämpiä algoritmeja ongelman ratkaisemiseksi.
pöytäkone 1, kannettavat 1–3: Debian GNU/Linux 12; pöytäkone 2: openSUSE Tumbleweed; NUC: openSUSE Leap 15.5; RPi 1: FreeBSD 14-RELEASE; RPi 2: LibreELEC 11