Stringek, azaz a szövegkezelés 1. rész

A szoftverek igen sok adata szöveges, hiszen a szoftvereknek velünk kell kommunikálnia, mi meg nem értünk binárisan (néhány igen elvetemült bitfejűtől eltekintve :) ). Ebből következően akkor tudunk programokat hatékonyan írni, ha az általunk használt programnyelv szövegkezelése fejlett, illetve ehhez olyan eszközöket biztosít, amivel a programozónak nem kell feltalálnia a spanyolviaszt. Igaz, a programnyelv fejlesztőinek ezért igen magasra van rakva a léc...

A python elég jó a szövegkezelésben, és lehet hogy pár helyen a php esetleg ráver (hiszen webnyelv, jónak kell lennie benne), összeségében nagyon jó eszközöket ad a kezünkbe, ha betartjuk a szabályait.
Mi a pythonban tehát a szöveg?
Nos, gyakorlatiasan nézve olyan karakterek sora, ami szöveghatárolókkal van közrezárva. pl.:
'ez egy szöveg'
"ez is egy szöveg"
"""Meg ez is egy szöveg.
De ez már többsörös is lehet. Vagyis többsoros :), biztos melegem van :D"""

Miért van többféle szöveghatároló?
A ' és a " között annyi a különbség, hogy az egyszeressel írt string tartalmazhat idézőjelet ("), a kétszeressel írt string pedig tartalmazhat egyszereset ('). A három kétszeres idézőjellel határolt szöveg pedig több sorban adható meg.

A stringek tartalmazhatnak 'nem látható' karaktereket, vagy vezérlőkaraktereket. Ezek beírási módját a python úgynevezett escape szekvenciákkal támogatja (ejtsd: eszkép). Ilyen pl. a közismert '\n', ami az új sor escape kódja. Nézzük:
>>> print 'új sor?\núj sor'
új sor?
új sor
>>> print "új sor?\núj sor"
új sor?
új sor

Látható tehát, hogy tagolt szöveget mindegyik határolóval előállíthatunk, de ha többsoros szöveget szeretnénk, a forráskódban az emberi szemünk számára a három kétszeres idézőjel lesz a legpraktikusabb.

A szövegeket össze is fűzhetjük:
>>> sz1="szöveg"
>>> sz2="másik"
>>> print sz1+sz2
szövegmásik

Vagy ismételhetjük:
>>> 'Haha'*5
'HahaHahaHahaHahaHaha'

A szövegek egyes karaktereit is lekérdezhetjük, sőt szeletelhetjük is, mint a listákat:
>>> sz="Ez egy elég hosszú szöveg"
>>> print sz
Ez egy elég hosszú szöveg
>>> print sz[5]
y
>>> print sz[12:]
 hosszú szöveg
>>> print sz[-5:]
öveg

Viszont nem módosíthatjuk a szöveg elemeit! Ez inkább tehát a tuple-kal teszi rokonná:
>>> sz[4]='X'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

A beépített len függvénnyel a stringek hosszát kaphatjuk meg:
>>> len(sz)
28

Mi magyarul beszélünk, ezért olyan karakterekre van szükségünk ami az ASCII kódtáblában nem található meg. A python 3-ban ez már nem probléma, mert belsőleg is unikódot használ a stringekhez, de akik még kénytelenek (szerintem még érdemesebb is) a 2-es sorozatnál maradni, nem feledkezhetnek meg erről, mert a python (2-es sorozat) a stringeket ASCII formában tárolja. Ez rengeteg bosszúságot okoz az embernek egyébként :(
Egy nem ASCII karaktereket is tartalmazó string így néz ki (maradjunk az előző stringünknél):
>>> sz
'Ez egy el\xc3\xa9g hossz\xc3\xba sz\xc3\xb6veg'

A nem ASCII karaktereket mindenféle krikszkraksszal kódolja nekünk a python.

Kérhetjük a pythonunkat, hogy ne stringként, hanem unicode objektumként tárolja a karakterláncunkat. Fontos megjegyezni a különbséget, mert bár a fejlesztők igyekeztek rugalmas átjárhatóságot biztosítani az unicode objektumok és a karakterláncok között, az egyes szövegkezelő függvényekkel meggyűlhet a bajunk, ráadásul a szövegkezelő függvények locale függők, tehát a bajok gyakran csak akkor jönnek ki, ha a locale szerint nem létező 8 bites karakter kerül a stringünkben. Pokollá teheti az életünket :). Ha a mi pythonunk fel van készítve erre, sok problémánk nem lesz. Nézzünk egy példát (nekem most a locale hu_HU.utf8):
>>> type('űűű')
<type 'str'>
>>> type(u'űűű')
<type 'unicode'>
>>> type(str(u'űűű'))
<type 'str'>
>>> type(str('űűű'))
<type 'str'>

Látható, hogy a két objektum különböző, és a konverziók megtörténnek. Hurrá!
Amennyiben Non Ascii tartalmú hibát kapunk, jusson eszünkbe, hogy ennek oka az unikód-problémából következik!

Sajnos sok string metódus egyszerűen nem működik akkor, ha a szöveg nem ASCII karaktereket tartalmaz (vagy nem úgy működik, ahogy kell):
>>> print 'űűű'.capitalize()
űűű
>>> print 'uuu'.capitalize()
Uuu
>>> print 'uuu'.upper()
UUU
>>> print 'űűű'.upper()
űűű

Python 3-mal nem próbálkoztam, csak remélem hogy ott ez a probléma így már nem él.

6 megjegyzés:

  1. Úgy látszik az upper működése több tényezőtől is függ. Most próbáltam ki win alatt, 2.6.6 pythonnal. Ha karakteres felületen indítom a pythont, akkor nem megy, ám az IDLE TkIntereses felületén már hibátlan. Furi...
    Íme:

    IDLE 2.6.6
    >>> print 'uuu'.upper()
    UUU
    >>> print 'üüü'.upper()
    ÜÜÜ
    >>> print 'űűű'.upper()
    ŰŰŰ
    >>>

    VálaszTörlés
  2. uh... a sevenhundredjét neki... másnál mi a tapasztalat?
    na meg az is lehet, hogy olyankor az alapértelmezett kódolás az idlében beállítódik a win-ben lévő kódlapra, ami ugye ott cp1250 (ha jól emlékszem). kódlappal mennie kell az str függvényeknek.
    import sys
    sys.getdefaultencoding()

    ez mit mond idle-ben és mit a winkonzolban?

    VálaszTörlés
  3. Mindkét helyen 'ascii'-t ad vissza.

    VálaszTörlés
  4. aha, akkor itt csak az lehet, hogy ilyenkor az os locale lesz a mérvadó mégiscsak

    VálaszTörlés
  5. Szia sipiatti!

    "Python 3-mal nem próbálkoztam, csak remélem hogy ott ez a probléma így már nem él."
    Igen.

    Python 2.6 esetében nem működik Python console-ban sem és programként futtava
    sem, még akkor sem ha megadjuk a character-kódolást és a nyelvi beállításokat is :

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import locale
    locale.setlocale(locale.LC_ALL, 'hu_HU')

    print ('ű'.capitalize())

    Lefuttatva szintén nem alakítja át.


    Viszont a Python 3.1 jól hajtja végre mind
    console-ban mind script-ként futtatva.
    print('ű'.capitalize())
    Ű
    >>>

    VálaszTörlés
  6. szuper, ezt jó tudni, köszönjük

    VálaszTörlés