Avoiding Windows backslash problems with Python’s raw strings

Olen Unix-tyyppi, mutta osallistujat Python-kursseillani käyttävät valtaosin Windowsia. Kun alamme puhua tiedostojen kanssa työskentelystä Pythonissa, joku haluaa väistämättä avata tiedoston käyttäen tiedoston koko polkua. Ja he päätyvät kirjoittamaan jotain tällaista:

filename = 'c:\abc\def\ghi.txt'

Mutta kun oppilaani yrittävät avata tiedoston, he huomaavat, että Python antaa heille virheilmoituksen, joka osoittaa, että tiedostoa ei ole olemassa! Toisin sanoen he kirjoittavat:

for one_line in open(filename): print(one_line)

Missä on ongelma? Tämä vaikuttaa aika tavalliselta Pythonilta, eikö?

Muista, että Pythonissa merkkijonot sisältävät yleensä merkkejä. Nämä merkit ovat normaalisti tulostettavia, mutta joskus on tilanteita, joissa haluat sisällyttää merkin, joka ei ole oikeasti tulostettavissa, kuten rivinvaihdon. Näissä tapauksissa Python (kuten monet ohjelmointikielet) sisältää erikoiskoodeja, jotka lisäävät erikoismerkin.

Tunnetuin esimerkki on newline eli ’\n’ eli ASCII 10. Jos haluat lisätä uuden rivin Python-merkkijonoon, voit tehdä sen käyttämällä ’\n’ keskellä. Esimerkiksi:

s = 'abc\ndef\nghi'

Kun tulostamme merkkijonon, näemme:

>>> print(s)abcdefghi

Mitä jos haluat tulostaa kirjaimellisen ’\n’-merkin koodissasi? Eli haluat backslash-merkin, jota seuraa ”n”? Silloin sinun on kaksinkertaistettava backslash:Merkkijonossa oleva ”\\” johtaa yhteen backslash-merkkiin. Seuraava ”n” on sitten normaali. Esimerkiksi:

s = 'abc\ndef\nghi'

Kun sanomme:

>>> print(s)abc\ndef\nghi

On melko hyvin tiedossa, että sinun on varottava tätä käännöstä, kun työskentelet \n:n kanssa. Mutta mitkä muut merkit vaativat sitä? Kävi ilmi, että enemmän kuin moni ehkä odottaa:

  • \a – hälytyskello (ASCII 7)
  • \b – backspace (ASCII
  • \f – form feed
  • \n – uusi rivi
  • \r – carriage return
  • \t – tabulaattori
  • \v. – pystysuora tabulaattori
  • \ooo – merkki, jolla on oktaaliarvo ooo
  • \xhh – merkki, jolla on heksalukuarvo hh
  • \N{nimi} – Unicode-merkki {nimi}
  • \uxxxx – Unicode-merkki, jolla on 16-alkuinen arvo.bittinen hex-arvo xxxx
  • \Uxxxxxxxxxx – Unicode-merkki 32-bittisellä hex-arvolla xxxxxxxx

Kokemukseni mukaan, on erittäin epätodennäköistä, että käytät joitakin näistä tarkoituksella. Tarkoitan, milloin viimeksi tarvitsit form feed -merkkiä? Tai pystysuoraa tabulaattoria? Tiedän – se oli suunnilleen samana päivänä, kun ajoit dinosauruksesi töihin kaivettuasi kaivon takapihallesi juomavettä varten.

Mutta melkein joka kerta, kun opetan Pythonia – eli joka päivä – joku luokassani törmää vahingossa johonkin näistä merkeistä. Tämä johtuu siitä, että näiden merkkien käyttämien backslashes-merkkien ja Windowsin poluissa käytettävien backslashes-merkkien yhdistelmä aiheuttaa väistämättömiä ja turhauttavia bugeja.

Muistatko tuon blogikirjoituksen alussa mainitsemani polun, joka vaikuttaa niin viattomalta?

filename = 'c:\abc\def\ghi.txt'

Se sisältää merkin ”\a”. Mikä tarkoittaa, että kun tulostamme sen:

>>> print(filename)c:bc\def\ghi.txt

Näetkö? ”\a” on kadonnut, tilalle on tullut hälytyskellomerkki. Jos olet onnekas.

Mitä voimme siis tehdä tälle? Kaksinkertaistamalla backslashit, tietysti. Sinun tarvitsee tuplata vain ne, jotka muuttuisivat erikoismerkeiksi edellä toistamastani taulukosta: Mutta muistatko todella, että ”\f” on erikoismerkki, mutta ”\g” ei? Todennäköisesti et.

Yleissääntöni on siis, ja sanon sen opiskelijoillekin, että heidän pitäisi aina tuplata Windows-polkujensa backslash-merkit. Toisin sanoen:

>>> filename = 'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt

Se toimii!

Mutta hetkinen: Kukaanhan ei halua oikeasti kahlailla polunnimiensä läpi ja tuplata jokaista backslashia? Ei tietenkään.

Tässä Pythonin raa’at merkkijonot voivat auttaa. Ajattelen raw-merkkijonoja kahdella eri tavalla:

  • what-you-see-is-what-you-get-merkkijonot
  • automaattisesti kaksinkertaistetut backslashit merkkijonoissa

Kummallakin tavalla, vaikutus on sama: Kaikki backslashit kaksinkertaistetaan, joten kaikki nämä ärsyttävät ja oudot erikoismerkit poistuvat. Mikä on hienoa, kun työskentelet Windows-polkujen kanssa.

Ainut, mitä sinun tarvitsee tehdä, on laittaa ”r” ennen avaavia lainausmerkkejä (yksinkertaisia tai kaksinkertaisia):

>>> filename = r'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt

Huomaa, että ”raaka merkkijono” ei oikeastaan ole lainkaan erilainen merkkijonotyyppi. Se on vain toinen tapa syöttää merkkijono Pythoniin. Jos tarkistat, type(tiedostonimi) on edelleen ”str”, mutta sen kaikki taustaviivat on tuplattu.

Viimeinen rivi: Jos käytät Windowsia, sinun pitäisi vain kirjoittaa kaikki kovakoodatut polunnimijonot raa’ana merkkijonona. Vaikka olisitkin Python-asiantuntija, voin kokemuksesta kertoa, että törmäät joskus tähän ongelmaan. Ja parhaimmillekin meistä tuon ”\f”-merkkijonon löytäminen voi olla aikaa vievää ja turhauttavaa.

PS: On totta, että Windows-käyttäjät voivat kiertää tämän ongelman käyttämällä vinoviivoja, kuten me Unix-käyttäjät teemme. Opiskelijoideni mielestä tämä on kuitenkin erityisen oudon näköistä, joten en näe sitä yleispätevänä ratkaisuna.

Rauhoituitko tästä artikkelista? Liity yli 11 000 muuhun kehittäjään, jotka saavat viikoittaisen ilmaisen ”Parempia kehittäjiä” -uutiskirjeeni. Saat joka maanantai tämän kaltaisen artikkelin ohjelmistokehityksestä ja Pythonista:

Vastaa

Sähköpostiosoitettasi ei julkaista.