1. 程式人生 > >python3-cookbook中一些關於字串和文字的處理方式

python3-cookbook中一些關於字串和文字的處理方式

1.查詢最大或最小的 N 個元素

heapq 模組有兩個函式:nlargest() 和 nsmallest() 可以完美解決這個問題。

import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
nbig = heapq.nlargest(3, nums)
nsmall = heapq.nsmallest(3, nums)

兩個函式都能接受一個關鍵字引數,用於更復雜的資料結構中:

portfolio = [
    {'name': 'IBM', 'shares': 100, 'price': 91.1},
    {'name': 'AAPL', 'shares': 50, 'price': 543.22},
    {'name': 'FB', 'shares': 200, 'price': 21.09},
    {'name': 'HPQ', 'shares': 35, 'price': 31.75},
    {'name': 'YHOO', 'shares': 45, 'price': 16.35},
    {'name': 'ACME', 'shares': 75, 'price': 115.65}
]
cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])

注:上面程式碼在對每個元素進行對比的時候,會以 price 的值進行比較。

當要查詢的元素個數相對比較小的時候,函式 nlargest() 和 nsmallest() 是很合適的。 如果你僅僅想查詢唯一的最小或最大(N=1)的元素的話,那麼使用 min() 和 max() 函式會更快些。 類似的,如果 N 的大小和集合大小接近的時候,通常先排序這個集合然後再使用切片操作會更快點 ( sorted(items)[:N] 或者是 sorted(items)[-N:] )。 需要在正確場合使用函式 nlargest() 和 nsmallest() 才能發揮它們的優勢 (如果 N 快接近集合大小了,那麼使用排序操作會更好些)。

2.怎樣在資料字典中執行一些計算操作(比如求最小值、最大值、排序等等)?

考慮下面的股票名和價格對映字典:

prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
}

為了對字典值執行計算操作,通常需要使用 zip() 函式先將鍵和值反轉過來。 比如,下面是查詢最小和最大股票價格和股票值的程式碼:

min_price = min(zip(prices.values(), prices.keys()))
# min_price is (10.75, 'FB')
max_price = max(zip(prices.values(), prices.keys()))
# max_price is (612.78, 'AAPL')
類似的,可以使用 zip() 和 sorted() 函式來排列字典資料:

prices_sorted = sorted(zip(prices.values(), prices.keys()))
# prices_sorted is [(10.75, 'FB'), (37.2, 'HPQ'),
#                   (45.23, 'ACME'), (205.55, 'IBM'),
#                   (612.78, 'AAPL')]

執行這些計算的時候,需要注意的是 zip() 函式建立的是一個只能訪問一次的迭代器。 比如,下面的程式碼就會產生錯誤:

prices_and_names = zip(prices.values(), prices.keys())
print(min(prices_and_names)) # OK
print(max(prices_and_names)) # ValueError: max() arg is an empty sequence

3.怎樣在兩個字典中尋尋找相同點(比如相同的鍵、相同的值等等)?

考慮下面兩個字典:

a = {
    'x' : 1,
    'y' : 2,
    'z' : 3
}

b = {
    'w' : 10,
    'x' : 11,
    'y' : 2
}

為了尋找兩個字典的相同點,可以簡單的在兩字典的 keys() 或者 items() 方法返回結果上執行集合操作。比如:

# Find keys in common
a.keys() & b.keys() # { 'x', 'y' }
# Find keys in a that are not in b
a.keys() - b.keys() # { 'z' }
# Find (key,value) pairs in common
a.items() & b.items() # { ('y', 2) }

這些操作也可以用於修改或者過濾字典元素。 比如,假如你想以現有字典構造一個排除幾個指定鍵的新字典。 下面利用字典推導來實現這樣的需求:

# Make a new dictionary with certain keys removed
c = {key:a[key] for key in a.keys() - {'z', 'w'}}
# c is {'x': 1, 'y': 2}

4.你有一個字典列表,你想根據某個或某幾個字典欄位來排序這個列表。

通過使用 operator 模組的 itemgetter 函式,可以非常容易的排序這樣的資料結構。 假設你從資料庫中檢索出來網站會員資訊列表,並且以下列的資料結構返回:

rows = [
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]

根據任意的字典欄位來排序輸入結果行是很容易實現的,程式碼示例:

from operator import itemgetter
rows_by_fname = sorted(rows, key=itemgetter('fname'))
rows_by_uid = sorted(rows, key=itemgetter('uid'))
print(rows_by_fname)
print(rows_by_uid)

最後,不要忘了這節中展示的技術也同樣適用於 min() 和 max() 等函式。比如:

>>> min(rows, key=itemgetter('uid'))
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}
>>> max(rows, key=itemgetter('uid'))
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
>>>

5.你需要將一個字串分割為多個欄位,但是分隔符(還有周圍的空格)並不是固定的。

string 物件的 split() 方法只適應於非常簡單的字串分割情形, 它並不允許有多個分隔符或者是分隔符周圍不確定的空格。 當你需要更加靈活的切割字串的時候,最好使用 re.split() 方法:

>>> line = 'asdf fjdk; afed, fjek,asdf, foo'
>>> import re
>>> re.split(r'[;,\s]\s*', line)
['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

函式 re.split() 是非常實用的,因為它允許你為分隔符指定多個正則模式。 比如,在上面的例子中,分隔符可以是逗號,分號或者是空格,並且後面緊跟著任意個的空格。 只要這個模式被找到,那麼匹配的分隔符兩邊的實體都會被當成是結果中的元素返回。 返回結果為一個欄位列表,這個跟 str.split() 返回值型別是一樣的。

6.你想在字串中搜索和匹配指定的文字模式

對於簡單的字面模式,直接使用 str.replace() 方法即可,比如:

>>> text = 'yeah, but no, but yeah, but no, but yeah'
>>> text.replace('yeah', 'yep')
'yep, but no, but yep, but no, but yep'
>>>

對於複雜的模式,請使用 re 模組中的 sub() 函式。 為了說明這個,假設你想將形式為 11/27/2012 的日期字串改成 2012-11-27 。示例如下:

>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> import re
>>> re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text)
'Today is 2012-11-27. PyCon starts 2013-3-13.'
>>>

sub() 函式中的第一個引數是被匹配的模式,第二個引數是替換模式。反斜槓數字比如 \3 指向前面模式的捕獲組號。

7.你想去掉文字字串開頭,結尾或者中間不想要的字元,比如空白。

strip() 方法能用於刪除開始或結尾的字元。 lstrip() 和 rstrip() 分別從左和從右執行刪除操作。 預設情況下,這些方法會去除空白字元,但是你也可以指定其他字元。比如:

>>> # Whitespace stripping
>>> s = ' hello world \n'
>>> s.strip()
'hello world'
>>> s.lstrip()
'hello world \n'
>>> s.rstrip()
' hello world'
>>>
>>> # Character stripping
>>> t = '-----hello====='
>>> t.lstrip('-')
'hello====='
>>> t.strip('-=')
'hello'
>>>

8.你想通過某種對齊方式來格式化字串

對於基本的字串對齊操作,可以使用字串的 ljust() , rjust() 和 center() 方法。比如:

>>> text = 'Hello World'
>>> text.ljust(20)
'Hello World         '
>>> text.rjust(20)
'         Hello World'
>>> text.center(20)
'    Hello World     '
>>>

所有這些方法都能接受一個可選的填充字元。比如:

>>> text.rjust(20,'=')
'=========Hello World'
>>> text.center(20,'*')
'****Hello World*****'
>>>

函式 format() 同樣可以用來很容易的對齊字串。 你要做的就是使用 <,> 或者 ^ 字元後面緊跟一個指定的寬度。比如:

>>> format(text, '>20')
'         Hello World'
>>> format(text, '<20')
'Hello World         '
>>> format(text, '^20')
'    Hello World     '
>>>

如果你想指定一個非空格的填充字元,將它寫到對齊字元的前面即可:

>>> format(text, '=>20s')
'=========Hello World'
>>> format(text, '*^20s')
'****Hello World*****'
>>>

當格式化多個值的時候,這些格式程式碼也可以被用在 format() 方法中。比如:

>>> '{:>10s} {:>10s}'.format('Hello', 'World')
'     Hello      World'
>>>

format() 函式的一個好處是它不僅適用於字串。它可以用來格式化任何值,使得它非常的通用。 比如,你可以用它來格式化數字:

>>> x = 1.2345
>>> format(x, '>10')
'    1.2345'
>>> format(x, '^10.2f')
'   1.23   '
>>>

9.你想建立一個內嵌變數的字串,變數被它的值所表示的字串替換掉。

Python並沒有對在字串中簡單替換變數值提供直接的支援。 但是通過使用字串的 format() 方法來解決這個問題。比如:

>>> s = '{name} has {n} messages.'
>>> s.format(name='Guido', n=37)
'Guido has 37 messages.'
>>>

或者,如果要被替換的變數能在變數域中找到, 那麼你可以結合使用 format_map() 和 vars() 。就像下面這樣:

>>> name = 'Guido'
>>> n = 37
>>> s.format_map(vars())
'Guido has 37 messages.'
>>>

10、你有一些長字串,想以指定的列寬將它們重新格式化。

使用 textwrap 模組來格式化字串的輸出。比如,假如你有下列的長字串:

s = "Look into my eyes, look into my eyes, the eyes, the eyes, \
the eyes, not around the eyes, don't look around the eyes, \
look into my eyes, you're under."

下面演示使用 textwrap 格式化字串的多種方式:

>>> import textwrap
>>> print(textwrap.fill(s, 70))
Look into my eyes, look into my eyes, the eyes, the eyes, the eyes,
not around the eyes, don't look around the eyes, look into my eyes,
you're under.
>>> print(textwrap.fill(s, 40, initial_indent='    '))
    Look into my eyes, look into my
eyes, the eyes, the eyes, the eyes, not
around the eyes, don't look around the
eyes, look into my eyes, you're under.

cookies:

判斷給定的日期字串是否匹配某種模式

re.match(r'^\d+/\d+/\d+$', dateStr)
re.match(r'^\d+-\d+-\d+$', dateStr)