1. 程式人生 > >Google's Python Class(二)——Python 字串

Google's Python Class(二)——Python 字串

Python 有一個內建的 string 類叫做 “str”,該類包含很多方便的特性(還有一個更老的模組叫 “string”,不過我們不會用到它)。String 常量可以被雙引號或者單引號包起來,不過通常會使用單引號。反斜線轉義符後面帶單引號和雙引號表示他們的常量——如 \n \’ \”。一個被雙引號包住的 String 常量裡面可以出現單引號,同樣地,單引號也可以包含雙引號。一個 String 常量可以跨越多行,但是必須在每行的結尾用反斜線 \ 將本行與新的一行隔開。包含在三引號的 String 常量,”“” 或者 ”’,可以包括多行的文字。

Python 的字串是“不可改變的”,這意味著字串被建立之後,就不可以更改(Java 的字串也使用了這種不可改變的規則)。由於字串不可以改變,我們構造*新的*字串,使得我們可以表示計算得到的值。所以舉個例子,對於表示式(’hello’ + ‘there’),接收 2 個字串 ‘hello’ 和 ‘there’,構建了一個新的字串 ‘hellothere’。

使用標準的 [] 語法可以訪問一個字串裡面的字元,並且像 Java 和 C++ 一樣,Python 也使用零基索引,所以如果一個 str 是 ‘hello’,那麼 str[1] 就是 ‘e’。如果索引超出了字串的邊界,那麼 Python 會報錯。如果不知道要做什麼,那麼 Python(不同於 Perl)會停止,而不是提供一個預設值。便利的“切片”語法(下面會介紹)可以從一個字串中提取出一些子字串。len(string) 函式返回一個字串的長度。事實上,[] 語法和 len() 函式可以用於任何序列型別——strings、lists等。Python 嘗試在不同的型別間,可以一致地使用運算操作。Python 菜鳥會明白:不要使用 “len” 作為變數名,從而避免無法使用 len() 函式。’+’ 運算子可以連線兩個字串。注意到下面的變數並不需要預先宣告,只需要賦值然後就可以使用了。

  s = 'hi'
  print s[1]          ## i
  print len(s)        ## 2
  print s + ' there'  ## hi there

不同於 Java,‘+’ 不會自動地將數字或者其它型別轉換成字串格式。而由於 str() 函式可以將數值轉換成字串格式,所以它們可以被組合成其它字串。

  pi = 3.14
  ##text = 'The value of pi is ' + pi      ## NO, does not work
  text = 'The value of pi is '  + str(pi)  ## yes

對於數字,標準的運算子,+,/,* 都能以通常的方式工作。沒有 ++ 運算子,但是有 +=,-= 等。如果你想要整除,那麼最正確的做法是使用 2 個斜槓——如 6 // 5 是 1。

“print” 操作符列印一個或多個 python 專案並且換行(在專案後面保留逗號可以阻止換行)。在字串常量前面加 ‘r’ 就成了一個 “raw” 字串常量,它裡面的所有字元都不會被反斜槓轉義,所以 r’x\nx’ 表示長度為 4 的字串 ‘x\nx’。’u’ 字首則表示後面跟的是 unicode 字串常量(Python 還有很多其它的 unicode 支援特性——下面的內容將會介紹)。

  raw = r'this\t\n and that'
  print raw     ## this\t\n and that

  multi = """It was the best of times.
  It was the worst of times."""

String 方法

一個方法就像一個函式,但是方法是執行在物件上。如果變數 s 是一個字串,那麼程式碼 s.lower() 表示在字串物件 s 上執行 lower() 方法並且返回結果(在一個物件上執行方法的思想是組成面向物件程式設計,OOP,的基本思想)。下面是最常用的 string 方法:

  • s.lower(),s.upper() —— 返回字串的小寫或者大寫

  • s.strip() —— 將字串開頭和結尾的空格都刪除,然後返回得到的新字串

  • s.isalpha()/s.isdigit()/s.isspace()… —— 測試字串裡面所有的字元是否在各種不同的類中

  • s.startswith(‘other’), s.endswith(‘other’) —— 測試字串是否以給定的 other 字串開頭或者結尾

  • s.find(‘other’) —— 在 s 中查詢給定的 other 字串(不是一個正則表示式),並且如果 s 存在 other 字串,那麼返回第一個出現該字串的首字母索引。如果不存在需要查詢的字串,則返回 -1。

  • s.replace(‘old’, ‘new’) —— 將 s 字串所有出現的 ‘old’ 替換成 ‘new’,並返回得到的新字串

  • s.split(‘delim’) —— 返回一個以給定分隔符分離出來的子字串組成的列表。分隔符不是一個正則表示式,它僅僅是文字。’aaa,bbb,ccc’.split(‘,’) -> [‘aaa’, ‘bbb’, ‘ccc’]。一個方便的方法:s.split()(沒有引數)可以以空格字元將字串分離開來。

  • s.join(list) —— 與 split() 相反,通過使用分隔符字串將給定的列表裡的元素組合成新的字串。例如,’—’.join([‘aaa’, ‘bbb’, ‘ccc’]) -> aaa—bbb—ccc

在 Google 上搜索 “python str” 可以得到包含所有字串方法的官網 python.org 字串方法

Python 沒有單獨的字元型別。而是使用類似 s[8] 這樣的表示式返回包含字元的長度為 1 的字串。對於長度為 1 的字串,==, <=, …這些運算子都可以使用,所以大部分情況下,你不需要一個單獨標量 “char” 型別。

String Slices

“slice” 語法是一種便利的用於分割序列的方法——通常用於 string 和 list。s[start:end] 表示以 start 開始直到 end 但不包括 end 的元素。假設 s = “Hello”。

  • s[1:4] 是 ‘ell’ —— 索引為 1 到但不包括索引為 4 的字元

  • s[1:] 是 ‘ello’ —— 省略某個索引,預設到開始或者結尾的字串

  • s[:] 是 ‘Hello’ —— 省略兩個索引通常會得到整個東西的拷貝(這是 Python 的方式來複制一個像 string 或者 list 的序列)

  • s[1:100] 是 ‘ello’ —— 索引太大的話,該索引會被截斷到字串的長度

標準的零基索引數字使得我們可以很容易在字串開始的附近訪問字元。作為替代方案,Python 使用負數來方便地訪問字串末尾的字元:s[-1] 是最後一個字元 ‘o’,s[-2] 是最後字元旁邊的 ‘l’,以此類推。負數索引從字串的末尾開始計數:

  • s[-1] 是 ‘o’ —— 最後一個字元(倒數第一個字元)

  • s[-4] 是 ‘e’ —— 倒數第四個字元

  • s[:-3] 是 ‘He’ —— 從第一個字元到但不包括倒數第三個字元

  • s[-3:] 是 ‘llo’ —— 從倒數第三個字元開始,一直到字串的末尾。

對於任意索引 n,一個關於 slice 的真理是:s[:n] + s[n:] == s。這甚至對於 n 是負數或者超出邊界都是適用的。或者說,s[:n] 和 s[n:] 總是可以把一個字串分成兩部分,儲存著所有字元。在以後討論到關於 list 的章節,slice 對於 list 也適用。

String %

Python 有一個類似 printf() 的機制將一些東西組合成一個字串。% 運算子和一個 printf 型別格式的字串放在左邊(%d int, %s string, %f/%g floating point),元組裡面相匹配的值放在右邊(一個元組由以逗號分隔開的值組成,通常被小括號包住):

  # % operator
  text = "%d little pigs come out or I'll %s and %s and %s" % (3, 'huff', 'puff', 'blow down')

上面一行有點長——假設你想要將它分成單獨的幾行。你不能像其它語言一樣僅僅在 ‘%’ 後面分行,因為 Python 預設把每一行當成一個獨立的語句(從好的方面想,這是為什麼我們不需要在每行最後輸入分號的原因)。為了解決這個問題,將整個表示式包進一個小括號中——然後表示式就可以跨越多行了。這種跨越多行程式碼的方法對於後面詳細介紹的各種不同的分組構造都適用:(), [], {}。

  # add parens to make the long-line work:
  text = ("%d little pigs come out or I'll %s and %s and %s" %
    (3, 'huff', 'puff', 'blow down'))

i18n Strings (Unicode)

常規的 Python 字串不是 unicode,它們只是普通的位元組。我們通過在字串常量前面加上 ‘u’ 字首來建立 unicode 字串:

> ustring = u'A unicode \u018e string \xf1'
> ustring
u'A unicode \u018e string \xf1'

一個 unicode string 是不同於常規 “str” string 的物件型別,但是 unicode string 是相容的(它們共享共同的超級類 “basestring”),並且即使傳進的是 unicode string 而不是常規的 string,類似正則表示式等各種不同的庫同樣可以正確地工作。

使用如 ‘utf-8’ 的編碼將 unicode string 轉換成位元組,即 unicode string 呼叫 ustring.encode(‘utf-8’) 方法。相反的,unicode(s, encoding) 函式將普通的位元組轉換成一個 unicode string:

## (ustring from above contains a unicode string)
> s = ustring.encode('utf-8')
> s
'A unicode \xc6\x8e string \xc3\xb1'  ## bytes of utf-8 encoding
> t = unicode(s, 'utf-8')             ## Convert bytes back to a unicode string
> t == ustring                      ## It's the same as the original, yay!
True

內建的 print 沒有完美支援 unicode string。你可以首先呼叫 encode() 將 unicode string 編碼成 utf-8 或者其它編碼方式,然後再打印出來。在讀取檔案的章節,有一個例子會介紹如何用一些編碼方式開啟一個文字檔案並且讀出 unicode strings。Note that unicode handling is one area where Python 3000 is significantly cleaned up vs. Python 2.x behavior described here.

If 語句

Python 不需要用 {} 將 if/loops/function 這樣的程式碼塊包括起來。相反,Python 使用冒號 (:) 和縮排/空格來把語句分組。if 語句的布林檢驗不需要放在小括號內(與 C++/Java 很大的不同),它有 elifelse 子句(幫助記憶:單詞 “elif” 與 “else” 的長度是一樣的)。

if 檢驗可以使用任何值。”zero” 值都可以當做是 flase: None, 0, empty string, empty list, empty dictionary。一個布林型別可以有兩個值:True 和 False(轉換成一個 int,就是 1 和 0)。Python 有常用的比較運算:==, !=, <, <=, >, >=。不同於 Java 和 C,== 被過載過,適用於 strings。布林運算子被寫成單詞 andornot(Python 不使用 C 風格的 && || !)。下面的程式碼看起來有點像是一個警察讓一個超速駕駛者把車靠到路邊的情景——注意到每一個 then/else 語句的程式碼塊是如何以 : 開頭,如何用縮排將語句分組:

  if speed >= 80:
    print 'License and registration please'
    if mood == 'terrible' or speed >= 100:
      print 'You have the right to remain silent.'
    elif mood == 'bad' or speed >= 90:
      print "I'm going to have to write you a ticket."
      write_ticket()
    else:
      print "Let's try to keep it under 80 ok?"

我發現當敲寫上述程式碼的時候,最容易犯的語法錯誤就是漏掉了冒號 “:”,很可能是因為對於 C++/Java,這個冒號是新的東西。還有就是不要講布林檢驗放到小括號裡面——那是 C++/Java 的習慣。雖然有一些人會覺得將程式碼放到不同的行可讀性會更好,但是如果程式碼比較短,你還是可以將程式碼放到與 “:” 同一行並且位於它後面,如下(這也適用於函式、迴圈等)。

  if speed >= 80: print 'You are so busted'
  else: print 'Have a nice day'

練習:string1.py