1-4:python使用字符串

1-4:python使用字符串



你已見過字符串,並且知道如何創建它們。你還學習瞭如何使用索引和切片來訪問字符串中 的字符。本章將介紹如何使用字符串來設置其他值的格式(比如便於打印),並大致瞭解使用字符串方法可完成的重要任務,如拆分、合併和查找等。

1、字符串基本操作

前一章說過,所有標準序列操作(索引、切片、乘法、成員資格檢查、長度、最小值和最 大值)都適用於字符串,但別忘了字符串是不可變的,因此所有的元素賦值和切片賦值都是非 法的。

>>> website = 'http://www.python.org'
>>> website[-3:] = 'com'
Traceback (most recent call last):
File "<pyshell#19>", line 1, in ?
website[-3:] = 'com'
TypeError: object doesn't support slice assignment

2、設置字符串的格式:精簡版

如果你是Python編程新手,可能不會用到所有的Python字符串格式設置選項,因此這裏介紹精簡版。如果你想了解詳情,請參閱接下來的3節,否則只需閱讀本節,再直接跳到4節。 將值轉換爲字符串並設置其格式是一個重要的操作,需要考慮衆多不同的需求,因此隨着時 間的流逝,Python提供了多種字符串格式設置方法。以前,主要的解決方案是使用字符串格式設 置運算符——百分號。這個運算符的行爲類似於C語言中的經典函數printf:在%左邊指定一個字符串(格式字符串),並在右邊指定要設置其格式的值。指定要設置其格式的值時,可使用單個 值(如字符串或數字),可使用元組(如果要設置多個值的格式),還可使用字典(這將在下一章 討論),其中最常見的是元組。

>>> format = "Hello, %s. %s enough for ya?"
>>> values = ('world', 'Hot')
>>> format % values
'Hello, world. Hot enough for ya?'

上述格式字符串中的%s稱爲轉換說明符,指出了要將值插入什麼地方。s意味着將值視爲字符串進行格式設置。如果指定的值不是字符串,將使用str將其轉換爲字符串。其他說明符將導致其他形式的轉換。例如,%.3f將值的格式設置爲包含3位小數的浮點數。

這種格式設置方法現在依然管用,且依然活躍在衆多代碼中,因此你很可能遇到。可能遇到的另一種解決方案是所謂的模板字符串。它使用類似於UNIX shell的語法,旨在簡化基本的格式設置機制,如下所示:

>>> from string import Template
>>> tmpl = Template("Hello, $who! $what enough for ya?")
>>> tmpl.substitute(who="Mars", what="Dusty")
'Hello, Mars! Dusty enough for ya?'

包含等號的參數稱爲關鍵字參數,第6章將詳細介紹這個術語。在字符串格式設置中,可將 關鍵字參數視爲一種向命名替換字段提供值的方式。

編寫新代碼時,應選擇使用字符串方法format,它融合並強化了早期方法的優點。使用這種方法時,每個替換字段都用花括號括起,其中可能包含名稱,還可能包含有關如何對相應的值進行轉換和格式設置的信息。

在最簡單的情況下,替換字段沒有名稱或將索引用作名稱。

>>> "{}, {} and {}".format("first", "second", "third")
'first, second and third'
>>> "{0}, {1} and {2}".format("first", "second", "third")
'first, second and third'

然而,索引無需像上面這樣按順序排列。

>>> "{3} {0} {2} {1} {3} {0}".format("be", "not", "or", "to")
'to be or not to be'

命名字段的工作原理與你預期的完全相同。

>>> from math import pi
>>> "{name} is approximately {value:.2f}.".format(value=pi, name="π")
'π is approximately 3.14.'

當然,關鍵字參數的排列順序無關緊要。在這裏,我還指定了格式說明符.2f,並使用冒號將其與字段名隔開。它意味着要使用包含2位小數的浮點數格式。如果沒有指定.2f,結果將如下(π在輸入法的字母中可以找到):

>>> "{name} is approximately {value}.".format(value=pi, name="π")
'π is approximately 3.141592653589793.'

最後,在Python 3.6中,如果變量與替換字段同名,還可使用一種簡寫。在這種情況下,可使用f字符串——在字符串前面加上f。

>>> from math import e
>>> f"Euler's constant is roughly {e}."
"Euler's constant is roughly 2.718281828459045."

在這裏,創建最終的字符串時,將把替換字段e替換爲變量e的值。這與下面這個更明確一些的表達式等價:

>>> "Euler's constant is roughly {e}.".format(e=e)
"Euler's constant is roughly 2.718281828459045."

3、設置字符串的格式:完整版

字符串格式設置涉及的內容很多,因此即便是這裏的完整版也無法全面探索所有的細節,而只是介紹主要的組成部分。這裏的基本思想是對字符串調用方法format,並提供要設置其格式的值。字符串包含有關如何設置格式的信息,而這些信息是使用一種微型格式指定語言(mini-language)指定的。每個值都被插入字符串中,以替換用花括號括起的替換字段。要在最終結果中包含花括號,可在格式字符串中使用兩個花括號(即{{或}})來指定。

>>> "{{ceci n'est pas une replacement field}}".format()
"{ceci n'est pas une replacement field}"

在格式字符串中,最激動人心的部分爲替換字段。替換字段由如下部分組成,其中每個部分都是可選的。

 字段名:索引或標識符,指出要設置哪個值的格式並使用結果來替換該字段。除指定值外,還可指定值的特定部分,如列表的元素。

 轉換標誌:跟在歎號後面的單個字符。當前支持的字符包括r(表示repr)、s(表示str)和a(表示ascii)。如果你指定了轉換標誌,將不使用對象本身的格式設置機制,而是使用指定的函數將對象轉換爲字符串,再做進一步的格式設置。

 格式說明符:跟在冒號後面的表達式(這種表達式是使用微型格式指定語言表示的)。格式說明符讓我們能夠詳細地指定最終的格式,包括格式類型(如字符串、浮點數或十六進制數),字段寬度和數的精度,如何顯示符號和千位分隔符,以及各種對齊和填充方式。

下面詳細介紹其中的一些要素。

3.1、替換字段名

在最簡單的情況下,只需向format提供要設置其格式的未命名參數,並在格式字符串中使用未命名字段。此時,將按順序將字段和參數配對。你還可給參數指定名稱,這種參數將被用於相 應的替換字段中。你可混合使用這兩種方法。

>>> "{foo} {} {bar} {}".format(1, 2, bar=4, foo=3)
'3 1 4 2'

還可通過索引來指定要在哪個字段中使用相應的未命名參數,這樣可不按順序使用未命名參數。

>>> "{foo} {1} {bar} {0}".format(1, 2, bar=4, foo=3)
'3 2 4 1'

然而,不能同時使用手工編號和自動編號,因爲這樣很快會變得混亂不堪。 你並非只能使用提供的值本身,而是可訪問其組成部分(就像在常規Python代碼中一樣),

如下所示:

>>> fullname = ["Alfred", "Smoketoomuch"]
>>> "Mr {name[1]}".format(name=fullname)
'Mr Smoketoomuch'
>>> import math
>>> tmpl = "The {mod.__name__} module defines the value {mod.pi} for π"
>>> tmpl.format(mod=math)
'The math module defines the value 3.141592653589793 for π'

如你所見,可使用索引,還可使用句點表示法來訪問導入的模塊中的方法、屬性、變量和函數(看起來很怪異的變量__name__包含指定模塊的名稱)。

3.2、基本轉換

指定要在字段中包含的值後,就可添加有關如何設置其格式的指令了。首先,可以提供一個轉換標誌。

>>> print("{pi!s} {pi!r} {pi!a}".format(pi="π"))
π 'π' '\u03c0'

上述三個標誌(s、r和a)指定分別使用str、repr和ascii進行轉換。函數str通常創建外觀普通的字符串版本(這裏沒有對輸入字符串做任何處理)。函數repr嘗試創建給定值的Python表示(這裏是一個字符串字面量)。函數ascii創建只包含ASCII字符的表示,類似於Python 2中的repr。

你還可指定要轉換的值是哪種類型,更準確地說,是要將其視爲哪種類型。例如,你可能提供一個整數,但將其作爲小數進行處理。爲此可在格式說明(即冒號後面)使用字符f(表示定點數)。

>>> "The number is {num}".format(num=42)
'The number is 42'
>>> "The number is {num:f}".format(num=42)
'The number is 42.000000'

你也可以將其作爲二進制數進行處理。

>>> "The number is {num:b}".format(num=42)
'The number is 101010'

這樣的類型說明符有多個,完整的清單見表3-1。

表3-1 字符串格式設置中的類型說明符

類型 含 義
b 將整數表示爲二進制數
c 將整數解讀爲Unicode碼點
d 將整數視爲十進制數進行處理,這是整數默認使用的說明符
e 使用科學表示法來表示小數(用e來表示指數)
E 與e相同,但使用E來表示指數
f 將小數表示爲定點數
F 與f相同,但對於特殊值(nan和inf),使用大寫表示
g 自動在定點表示法和科學表示法之間做出選擇。這是默認用於小數的說明符,但在默認情況下至少有1位小數
G 與g相同,但使用大寫來表示指數和特殊值
n 與g相同,但插入隨區域而異的數字分隔符
o 將整數表示爲八進制數
s 保持字符串的格式不變,這是默認用於字符串的說明符
x 將整數表示爲十六進制數並使用小寫字母
X 與x相同,但使用大寫字母
% 將數表示爲百分比值(乘以100,按說明符f設置格式,再在後面加上%)

3.3、寬度、精度和千位分隔符

設置浮點數(或其他更具體的小數類型)的格式時,默認在小數點後面顯示6位小數,並根據需要設置字段的寬度,而不進行任何形式的填充。當然,這種默認設置可能不是你想要的,在這種情況下,可根據需要在格式說明中指定寬度和精度。

寬度是使用整數指定的,如下所示:

>>> "{num:10}".format(num=3)
'         3'
>>> "{name:10}".format(name="Bob")
'Bob       '  

如你所見,數和字符串的對齊方式不同。對齊將在下一節介紹。

精度也是使用整數指定的,但需要在它前面加上一個表示小數點的句點。

>>> "Pi day is {pi:.2f}".format(pi=pi)
'Pi day is 3.14'

這裏顯式地指定了類型f,因爲默認的精度處理方式稍有不同(相關的規則請參閱“Python庫參考手冊”)。當然,可同時指定寬度和精度。

>>> "{pi:10.2f}".format(pi=pi)
'      3.14'

實際上,對於其他類型也可指定精度,但是這樣做的情形不太常見。

>>> "{:.5}".format("Guido van Rossum")
'Guido'

最後,可使用逗號來指出你要添加千位分隔符。

>>> 'One googol is {:,}'.format(10**100)
'One googol is 10,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000'

同時指定其他格式設置元素時,這個逗號應放在寬度和表示精度的句點之間①。

3.4、符號、對齊和用 0 填充

有很多用於設置數字格式的機制,比如便於打印整齊的表格。在大多數情況下,只需指定寬度和精度,但包含負數後,原本漂亮的輸出可能不再漂亮。另外,正如你已看到的,字符串和數的默認對齊方式不同。在一欄中同時包含字符串和數時,你可能想修改默認對齊方式。在指定寬度和精度的數前面,可添加一個標誌。這個標誌可以是零、加號、減號或空格,其中零表示使用0來填充數字。

>>> '{:010.2f}'.format(pi)
'0000003.14'

要指定左對齊、右對齊和居中,可分別使用<、>和^。

>>> print('{0:<10.2f}\n{0:^10.2f}\n{0:>10.2f}'.format(pi))
3.14
	3.14  
		3.14

可以使用填充字符來擴充對齊說明符,這樣將使用指定的字符而不是默認的空格來填充。

>>> "{:$^15}".format(" WIN BIG ")
'$$$ WIN BIG $$$'

還有更具體的說明符=,它指定將填充字符放在符號和數字之間。

>>> print('{0:10.2f}\n{1:10.2f}'.format(pi, -pi))
      3.14
     -3.14
>>> print('{0:10.2f}\n{1:=10.2f}'.format(pi, -pi))
      3.14
-     3.14

如果要給正數加上符號,可使用說明符+(將其放在對齊說明符後面),而不是默認的-。如果將符號說明符指定爲空格,會在正數前面加上空格而不是+。

>>> print('{0:-.2}\n{1:-.2}'.format(pi, -pi)) #默認設置
3.1
-3.1
>>> print('{0:+.2}\n{1:+.2}'.format(pi, -pi))
+3.1
-3.1
>>> print('{0: .2}\n{1: .2}'.format(pi, -pi))
 3.1
-3.1

需要介紹的最後一個要素是井號(#)選項,你可將其放在符號說明符和寬度之間(如果指定了這兩種設置)。這個選項將觸發另一種轉換方式,轉換細節隨類型而異。例如,對於二進制、八進制和十六進制轉換,將加上一個前綴。

——————————

① 如果要使用隨區域而異的千位分隔符,應使用類型說明符n。

>>> "{:b}".format(42)
'101010'
>>> "{:#b}".format(42)
'0b101010'

對於各種十進制數,它要求必須包含小數點(對於類型g,它保留小數點後面的零)。

>>> "{:g}".format(42)
'42'
>>> "{:#g}".format(42)
'42.0000'

在代碼清單3-1所示的示例中,我分兩次設置了字符串的格式,其中第一次旨在插入最終將作爲格式說明符的字段寬度。這是因爲這些信息是由用戶提供的,我無法以硬編碼的方式指定字段寬度。

代碼清單3-1 字符串格式設置示例

# 根據指定的寬度打印格式良好的價格列表

width = int(input('Please enter width: '))

price_width = 10
item_width = width - price_width

header_fmt = '{{:{}}}{{:>{}}}'.format(item_width, price_width)
fmt        = '{{:{}}}{{:>{}.2f}}'.format(item_width, price_width)

print('=' * width)

print(header_fmt.format('Item', 'Price'))

print('-' * width)

print(fmt.format('Apples', 0.4))
print(fmt.format('Pears', 0.5))
print(fmt.format('Cantaloupes', 1.92))
print(fmt.format('Dried Apricots (16 oz.)', 8))
print(fmt.format('Prunes (4 lbs.)', 12))

print('=' * width)

這個程序的運行情況類似於下面這樣:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-75onHNVD-1581400733723)(C:\Users\pc\AppData\Local\Temp\1581391514819.png)]

4、字符串方法

前面介紹了列表的方法,而字符串的方法要多得多,因爲其很多方法都是從模塊string那裏“繼承”而來的。(在較早的Python版本中,這些方法爲模塊string中的函數。如果需要,現在依然能夠找到這些函數。)

字符串的方法太多了,這裏只介紹一些最有用的。完整的字符串方法清單請參閱附錄B。這裏描述字符串的方法時,將列出其他相關的方法。如果這些相關方法在本章做了介紹,將用“另請參見”標識,否則用“附錄B”標識。

模塊string未死

雖然字符串方法完全蓋住了模塊string的風頭,但這個模塊包含一些字符串沒有的常量和函數。下面就是模塊string中幾個很有用的常量①。 

 string.digits:包含數字0~9的字符串。

 string.ascii_letters:包含所有ASCII字母(大寫和小寫)的字符串。

 string.ascii_lowercase:包含所有小寫ASCII字母的字符串。

 string.printable:包含所有可打印的ASCII字符的字符串。

 string.punctuation:包含所有ASCII標點字符的字符串。

 string.ascii_uppercase:包含所有大寫ASCII字母的字符串。

雖然說的是ASCII字符,但值實際上是未解碼的Unicode字符串。

4.1 center

方法center通過在兩邊添加填充字符(默認爲空格)讓字符串居中。

>>> "The Middle by Jimmy Eat World".center(39)
' The Middle by Jimmy Eat World '
>>> "The Middle by Jimmy Eat World".center(39, "*")
'*****The Middle by Jimmy Eat World*****'

附錄B:ljust、rjust和zfill。

4.2 find

方法find在字符串中查找子串。如果找到,就返回子串的第一個字符的索引,否則返回-1。

>>> 'With a moo-moo here, and a moo-moo there'.find('moo')
7
>>> title = "Monty Python's Flying Circus"
>>> title.find('Monty')
0
>>> title.find('Python')
>>> title.find('Flying')
15
>>> title.find('Zirquss')
-1

第2章初識成員資格時,我們在垃圾郵件過濾器中檢查主題是否包含’$$$’。這種檢查也可使用find來執行。(在Python 2.3之前的版本中,這種做法也管用,但in只能用於檢查單個字符是否包含在字符串中。)

>>> subject = '$$$ Get rich now!!! $$$'
>>> subject.find('$$$')
0

注意 字符串方法find返回的並非布爾值。如果find像這樣返回0,就意味着它在索引0處找到了指定的子串。

你還可指定搜索的起點和終點(它們都是可選的)。

>>> subject = '$$$ Get rich now!!! $$$'
>>> subject.find('$$$')
0
>>> subject.find('$$$', 1) # 只指定了起點
20
>>> subject.find('!!!')
16
>>> subject.find('!!!', 0, 16) # 同時指定了起點和終點
-1 

請注意,起點和終點值(第二個和第三個參數)指定的搜索範圍包含起點,但不包含終點。

這是Python慣常的做法。

附錄B:rfind、index、rindex、count、startswith、endswith。

4.3 join

join是一個非常重要的字符串方法,其作用與split相反,用於合併序列的元素。

>>> seq = [1, 2, 3, 4, 5]
>>> sep = '+'
>>> sep.join(seq) # 嘗試合併一個數字列表
Traceback (most recent call last):
 File "<stdin>", line 1, in ?
TypeError: sequence item 0: expected string, int found
>>> seq = ['1', '2', '3', '4', '5']
>>> sep.join(seq) # 合併一個字符串列表
'1+2+3+4+5'
>>> dirs = '', 'usr', 'bin', 'env'
>>> '/'.join(dirs)
'/usr/bin/env'
>>> print('C:' + '\\'.join(dirs))
C:\usr\bin\env

如你所見,所合併序列的元素必須都是字符串。注意到在最後兩個示例中,我使用了一系列目錄,並按UNIX和DOS/Windows的約定設置其格式:通過使用不同的分隔符(並在DOS版本中添加了盤符)。

另請參見:split。

4.4 lower

方法lower返回字符串的小寫版本。

>>> 'Trondheim Hammer Dance'.lower()
'trondheim hammer dance'

在你編寫代碼時,如果不想區分字符串的大小寫(即忽略大小寫的差別),這將很有用。例如,假設你要檢查列表中是否包含指定的用戶名。如果列表包含字符串’gumby’,而指定的用戶名爲’Gumby’,你將找不到它。

>>> if 'Gumby' in ['gumby', 'smith', 'jones']: print('Found it!')
...
>>>

當然,如果列表包含’Gumby’,而指定的用戶名爲’gumby’或’GUMBY’,結果同樣找不到。對於這種問題,一種解決方案是在存儲和搜索時,將所有的用戶名都轉換爲小寫。這樣做的代碼類似於下面這樣:

>>> name = 'Gumby'
>>> names = ['gumby', 'smith', 'jones']
>>> if name.lower() in names: print('Found it!')
...
Found it!
>>>

另請參見:islower、istitle、isupper、translate。

附錄B:capitalize、casefold、swapcase、title、upper。

詞首大寫

一個與lower相關的方法是title(參見附錄B)。它將字符串轉換爲詞首大寫,即所有單詞的首字母都大寫,其他字母都小寫。然而,它確定單詞邊界的方式可能導致結果不合理。
>>> "that's all folks".title()
"That'S All, Folks"

另一種方法是使用模塊string中的函數capwords。
>>> import string
>>> string.capwords("that's all, folks")
That's All, Folks"

當然,要實現真正的詞首大寫(根據你採用的寫作風格,冠詞、並列連詞以及不超過5個字母的介詞等可能全部小寫),你得自己編寫代碼。

4.5 replace

方法replace將指定子串都替換爲另一個字符串,並返回替換後的結果。

>>> 'This is a test'.replace('is', 'eez')
'Theez eez a test'

如果你使用過字處理程序的“查找並替換”功能,一定知道這個方法很有用。

另請參見:translate。

附錄B:expandtabs。

4.6 split

split是一個非常重要的字符串方法,其作用與join相反,用於將字符串拆分爲序列。

>>> '1+2+3+4+5'.split('+')
['1', '2', '3', '4', '5']
>>> '/usr/bin/env'.split('/')
['', 'usr', 'bin', 'env']
>>> 'Using the default'.split()
['Using', 'the', 'default'] 

注意,如果沒有指定分隔符,將默認在單個或多個連續的空白字符(空格、製表符、換行符等)處進行拆分。

另請參見:join。

附錄B:partition、rpartition、rsplit、splitlines。

4.7 strip

方法strip將字符串開頭和末尾的空白(但不包括中間的空白)刪除,並返回刪除後的結果。

>>> ' internal whitespace is kept '.strip()
'internal whitespace is kept'

與lower一樣,需要將輸入與存儲的值進行比較時,strip很有用。回到前面介紹lower時使用的用戶名示例,並假定用戶輸入用戶名時不小心在末尾加上了一個空格。

>>> names = ['gumby', 'smith', 'jones']
>>> name = 'gumby '
>>> if name in names: print('Found it!')
...
>>> if name.strip() in names: print('Found it!')
...
Found it!
>>>

你還可在一個字符串參數中指定要刪除哪些字符。

>>> '*** SPAM * for * everyone!!! ***'.strip(' *!')
'SPAM * for * everyone'

這個方法只刪除開頭或末尾的指定字符,因此中間的星號未被刪除。

附錄B:lstrip、rstrip。

4.8 translate

方法translate與replace一樣替換字符串的特定部分,但不同的是它只能進行單字符替換。

這個方法的優勢在於能夠同時替換多個字符,因此效率比replace高。

這個方法的用途很多(如替換換行符或其他隨平臺而異的特殊字符),但這裏只介紹一個比較簡單(也有點傻)的示例。假設你要將一段英語文本轉換爲帶有德國口音的版本,爲此必須將字符c和s分別替換爲k和z。

然而,使用translate前必須創建一個轉換表。這個轉換表指出了不同Unicode碼點之間的轉換關係。要創建轉換表,可對字符串類型str調用方法maketrans,這個方法接受兩個參數:兩個長度相同的字符串,它們指定要將第一個字符串中的每個字符都替換爲第二個字符串中的相應字符①。就這個簡單的示例而言,代碼類似於下面這樣:

>>> table = str.maketrans('cs', 'kz')  

如果願意,可查看轉換表的內容,但你看到的只是Unicode碼點之間的映射。

>>> table
{115: 122, 99: 107}

創建轉換表後,就可將其用作方法translate的參數。

>>> 'this is an incredible test'.translate(table)
'thiz iz an inkredible tezt'

調用方法maketrans時,還可提供可選的第三個參數,指定要將哪些字母刪除。例如,要模仿語速極快的德國口音,可將所有的空格都刪除。

>>> table = str.maketrans('cs', 'kz', ' ')
>>> 'this is an incredible test'.translate(table)
'thizizaninkredibletezt'

另請參見:replace、lower。

4.9 判斷字符串是否滿足特定的條件

很多字符串方法都以is打頭,如isspace、isdigit和isupper,它們判斷字符串是否具有特定的性質(如包含的字符全爲空白、數字或大寫)。如果字符串具備特定的性質,這些方法就返回True,否則返回False。

附錄B:isalnum、isalpha、isdecimal、isdigit、isidentifier、islower、isnumeric、isprintable、isspace、istitle、isupper。

——————————

① 也可傳入下一章將介紹的字典,將一些字符映射到其他字符(如果要刪除這些字符,則映射到None)。

5、小結

本章介紹了字符串的兩個重要方面。

 字符串格式設置:求模運算符(%)可用於將值合併爲包含轉換標誌(如%s)的字符串,這讓你能夠以衆多方式設置值的格式,如左對齊或右對齊,指定字段寬度和精度,添加符號(正號或負號)以及在左邊填充0等。

 字符串方法:字符串有很多方法,有些很有用(如split和join),有些很少用到(如istitle和capitalize)。

5.1 本章介紹的新函數

函 數 描 述
string.capwords(s[, sep]) 使用split根據sep拆分s,將每項的首字母大寫,再以空格爲分隔符將它們合併起來
ascii(obj) 創建指定對象的ASCII表示

5.2 預告

列表、字符串和字典是三種最重要的Python數據類型。你已經學習了列表和字符串,接下來將介紹什麼呢?下一章將介紹字典,它不僅支持整數索引,還支持其他類型的鍵(如字符串或元組)。另外,字典還提供了一些方法,但是數量無法與字符串相比。

發佈了116 篇原創文章 · 獲贊 130 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章