最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python字符串從入門到精通的實戰(zhàn)指南

 更新時間:2026年06月01日 09:28:28   作者:碼流怪俠  
字符串是 Python 中最常用的數據類型之一,無論是數據處理、Web 開發(fā)、日志分析還是音視頻編解碼,字符串操作都是基本功,本文從創(chuàng)建到正則實戰(zhàn),帶你徹底搞懂 Python 字符串,需要的朋友可以參考下

1. 字符串創(chuàng)建與基本操作

1.1 四種創(chuàng)建方式

Python 提供了四種引號方式來創(chuàng)建字符串,它們在語法上等價,但各有適用場景:

# ========== 四種創(chuàng)建方式 ==========
s1 = '單引號字符串'          # 最常用,適合短文本
s2 = "雙引號字符串"          # 與單引號等價,適合包含單引號的內容
s3 = '''三重單引號
可以換行
多行文本'''                  # 多行字符串
s4 = """三重雙引號
也可以換行
多行文本"""                  # 多行字符串,常作文檔字符串(docstring)

print(type(s1))  # <class 'str'>
print(s1)        # 單引號字符串
print(s3)        # 三重單引號\n可以換行\(zhòng)n多行文本(實際輸出會換行)

單引號 vs 雙引號的選擇原則:

# 原則:外層引號與內層引號不同,避免轉義
msg1 = "It's a beautiful day"     # ? 外雙內單,無需轉義
msg2 = 'He said "Hello"'          # ? 外單內雙,無需轉義
msg3 = 'It\'s a beautiful day'    # ?? 可以但沒必要,轉義降低可讀性

# 團隊規(guī)范:選擇一種風格保持統(tǒng)一,推薦雙引號(PEP 257 docstring 用三雙引號)

1.2 原始字符串與轉義

# ========== 轉義字符速查 ==========
print("換行符: \n")       # 換行
print("制表符: \t")       # 制表
print("反斜杠: \\")       # 反斜杠本身
print("單引號: \'")       # 單引號
print("雙引號: \"")       # 雙引號
print("回車符: \r")       # 回車(覆蓋行首)

# ========== 原始字符串 r"" ==========
# Windows 路徑 —— 不用 r 就得雙重轉義
path1 = "C:\\Users\\yance\\Desktop"    # 普通字符串,每個 \ 都要轉義
path2 = r"C:\Users\yance\Desktop"      # 原始字符串,所見即所得 ?

# 正則表達式 —— 不用 r 就變成"轉義地獄"
import re
# 匹配數字 \d,不用 r 的話:
re.compile("\\d+")    # Python 先轉義為 \d,re 再解釋為數字
# 用 r 的話:
re.compile(r"\d+")    # 直達正則引擎,清晰明了 ?

# ?? 原始字符串的陷阱:不能以奇數個反斜杠結尾
# r"hello\"   # SyntaxError! 反斜杠轉義了結尾引號
r"hello\\"   # ? 等價于 "hello\\"

1.3 f-string 格式化(Python 3.6+)

Python 歷史上出現了三種字符串格式化方式,f-string 是目前的最優(yōu)解:

name = "yance"
age = 28
score = 95.678

# ========== 三種格式化方式對比 ==========

# ? % 格式化(C 風格,老舊不推薦)
print("Name: %s, Age: %d" % (name, age))

# ? str.format()(Python 2.6+,可讀性一般)
print("Name: {}, Age: {}".format(name, age))
print("Name: {0}, Age: {1}".format(name, age))

# ? f-string(Python 3.6+,推薦 ?)
print(f"Name: {name}, Age: {age}")

# ========== f-string 高級用法 ==========

# 表達式求值
print(f"Next year: {age + 1}")              # 直接運算
print(f"Name upper: {name.upper()}")         # 調用方法
print(f"Len: {len(name)}")                   # 調用函數

# 格式控制:{value:format_spec}
print(f"Score: {score:.2f}")                 # 保留2位小數 → 95.68
print(f"Score: {score:>10.2f}")              # 右對齊,寬度10 →     95.68
print(f"Score: {score:<10.2f}")              # 左對齊 → 95.68
print(f"Score: {score:^10.2f}")              # 居中 →   95.68
print(f"Score: {score:0>10.2f}")             # 前補零 → 0000095.68

# 數字格式化
num = 1234567
print(f"千分位: {num:,}")                    # 1,234,567
print(f"百分比: {0.856:.1%}")                # 85.6%
print(f"科學計數: {num:.2e}")                # 1.23e+06
print(f"二進制: {42:b}")                     # 101010
print(f"十六進制: {255:x}")                  # ff
print(f"八進制: {255:o}")                    # 377

# Python 3.8+ 調試語法 =(變量名=值)
x = 42
print(f"{x = }")           # x = 42
print(f"{x * 2 = }")       # x * 2 = 84
print(f"{name = !r}")       # name = 'yance'  (!r 顯示引號)

格式化方式對比總結:

方式版本可讀性性能推薦度
%s全版本★★☆★★☆?? 僅維護老代碼
.format()2.6+★★★★★★?? 兼容舊版本時用
f-string3.6+★★★★★★★★? 首選

1.4 字符串拼接與乘法

# ========== 拼接方式 ==========
# ? + 號拼接(少量字符串)
greeting = "Hello" + " " + "World"    # "Hello World"

# ? join 拼接(大量字符串,性能最優(yōu))?
words = ["Python", "is", "awesome"]
sentence = " ".join(words)             # "Python is awesome"

# ? f-string 拼接(現代寫法)?
lang = "Python"
sentence = f"{lang} is awesome"

# ?? 性能對比:+ 號 vs join
import time

def concat_plus(n=100000):
    s = ""
    for i in range(n):
        s += "a"
    return s

def concat_join(n=100000):
    return "".join("a" for _ in range(n))

# join 比 + 快約 2-3 倍(CPython 對 += 有優(yōu)化,但 join 仍更優(yōu))

# ========== 字符串乘法 ==========
separator = "-" * 40           # "----------------------------------------"
indent = "    " * 3            # 12個空格
pattern = "ab" * 5             # "ababababab"
print(separator)

2. 索引、切片與步進

2.1 索引機制

Python 字符串支持雙向索引:正索引從 0 開始,負索引從 -1 開始。

字符串:  P   y   t   h   o   n
正索引:  0   1   2   3   4   5
負索引: -6  -5  -4  -3  -2  -1
s = "Python"

# ========== 正索引 ==========
print(s[0])     # 'P'    首字符
print(s[5])     # 'n'    末字符

# ========== 負索引 ==========
print(s[-1])    # 'n'    末字符(最常用!)
print(s[-6])    # 'P'    首字符
print(s[-2])    # 'o'    倒數第二個

# ========== 索引越界 ==========
# s[6]         # IndexError: string index out of range
# s[-7]        # IndexError: string index out of range

2.2 切片 [start:stop:step]

切片是 Python 最優(yōu)雅的特性之一,左閉右開,不會越界報錯:

s = "ABCDEFGHIJ"
#    0123456789

# ========== 基礎切片 ==========
print(s[2:5])     # 'CDE'     索引 2,3,4(不含5)
print(s[:5])      # 'ABCDE'   從頭到索引4
print(s[5:])      # 'FGHIJ'   從索引5到末尾
print(s[:])       # 'ABCDEFGHIJ'  完整拷貝

# ========== 負索引切片 ==========
print(s[-3:])     # 'HIJ'     最后3個字符
print(s[:-3])     # 'ABCDEFG'  除最后3個之外
print(s[-5:-2])   # 'FGH'     倒數第5到倒數第3(不含-2)

# ========== 越界安全 ==========
print(s[5:100])   # 'FGHIJ'   不報錯,取到末尾
print(s[100:200]) # ''        不報錯,返回空串

2.3 步進 step

步進(step)控制切片的方向和跨度:

s = "ABCDEFGHIJ"

# ========== 正向步進 ==========
print(s[::2])     # 'ACEGI'   每隔1個取1個(奇數位)
print(s[1::2])    # 'BDFHJ'   偶數位
print(s[::3])     # 'ADGJ'    每隔2個取1個

# ========== 反向步進(負步進) ==========
print(s[::-1])    # 'JIHGFEDCBA'  反轉字符串!最常用技巧 ?
print(s[::-2])    # 'JHFDB'       反向每隔1個取1個
print(s[8:2:-1])  # 'IHGFED'      從索引8反向切到索引3
print(s[7:2:-2])  # 'HFD'         反向每隔1個

# ========== 步進方向與起止方向必須一致 ==========
print(s[2:8:-1])  # ''  步進是反向,但起止是正向 → 空串
print(s[8:2:1])   # ''  步進是正向,但起止是反向 → 空串

切片速記口訣:

切片左閉右開取,起止省略到兩頭。
步進為正從左走,步進為負往右搜。
方向沖突空串還,越界安全不報錯。

2.4 切片賦值?—— 字符串不可變!

s = "Python"
# s[0] = "J"    # TypeError: 'str' object does not support item assignment

# 修改字符串的唯一方式:創(chuàng)建新字符串
s = "J" + s[1:]   # 'Jython'  拼接新串
s = s.replace("J", "P")  # 'Python' 用方法返回新串

# 不可變的好處:
# 1. 可以安全地作為字典的 key
# 2. 多個變量可以共享同一字符串對象(內存優(yōu)化)
# 3. 線程安全

3. 常用方法詳解

3.1 查找類:find / index / count / rfind

s = "Hello, Python! Python is great."

# ========== find / rfind ==========
# find(sub, start, end) → 返回子串首次出現的索引,找不到返回 -1
print(s.find("Python"))       # 7    首次出現
print(s.find("Python", 10))   # 15   從索引10開始找
print(s.find("Java"))         # -1   找不到
print(s.rfind("Python"))      # 15   最后一次出現的索引

# ========== index / rindex ==========
# index 與 find 功能相同,但找不到時拋出 ValueError
print(s.index("Python"))      # 7
# s.index("Java")            # ValueError: substring not found

# ========== count ==========
print(s.count("Python"))      # 2    出現次數
print(s.count("o"))           # 2
print(s.count("z"))           # 0

# ========== find vs index 選擇建議 ==========
# 確定子串存在時用 index(找不到是異常,暴露 bug)
# 不確定子串是否存在時用 find(找不到返回 -1,正常邏輯)

3.2 替換:replace

s = "Hello, World! World is beautiful."

# ========== 基本替換 ==========
print(s.replace("World", "Python"))
# "Hello, Python! Python is beautiful."
# 默認替換所有出現

# ========== 限制替換次數 ==========
print(s.replace("World", "Python", 1))
# "Hello, Python! World is beautiful."  只替換第1個

# ========== 鏈式替換 ==========
result = s.replace("World", "Python").replace("beautiful", "awesome")
print(result)
# "Hello, Python! Python is awesome."

# ?? replace 返回新字符串,原字符串不變(字符串不可變?。?
original = "abc"
new = original.replace("b", "X")   # "aXc"
print(original)                     # "abc"  原串未變

3.3 分割與合并:split / rsplit / splitlines / join

# ========== split / rsplit ==========
csv_data = "name,age,city"
print(csv_data.split(","))         # ['name', 'age', 'city']

# 限制分割次數
text = "a-b-c-d-e"
print(text.split("-", 2))          # ['a', 'b', 'c-d-e']  從左分割2次
print(text.rsplit("-", 2))         # ['a-b-c', 'd', 'e']   從右分割2次

# 默認按空白字符分割(空格、Tab、換行都行)
messy = "  hello   world  \t python  \n  "
print(messy.split())               # ['hello', 'world', 'python']

# ========== splitlines ==========
multiline = "第一行\(zhòng)n第二行\(zhòng)r\n第三行\(zhòng)r第四行"
print(multiline.splitlines())      # ['第一行', '第二行', '第三行', '第四行']
# 自動識別 \n, \r\n, \r 三種換行符

# ========== join(split 的逆操作)==========
words = ["Python", "is", "awesome"]
print(" ".join(words))             # "Python is awesome"
print("-".join(words))             # "Python-is-awesome"
print("".join(words))              # "Pythonisawesome"

# 經典用法:路徑拼接
import os
dirs = ["home", "yance", "projects"]
path = "/".join(dirs)              # "home/yance/projects"
# 實際項目推薦 os.path.join() 或 pathlib

# ?? join 只能連接字符串列表,數字需要先轉換
nums = [1, 2, 3]
# ",".join(nums)                   # TypeError!
print(",".join(str(n) for n in nums))  # "1,2,3" ?

3.4 去除空白:strip / lstrip / rstrip

# ========== 基本去空白 ==========
s = "  Hello, World!  "
print(s.strip())      # "Hello, World!"   兩端去除
print(s.lstrip())     # "Hello, World!  " 去除左端
print(s.rstrip())     # "  Hello, World!" 去除右端

# ========== 去除指定字符 ==========
# strip(chars) —— 去除兩端所有在 chars 中的字符(不是去除子串?。?
s2 = "***Hello***"
print(s2.strip("*"))        # "Hello"

s3 = "xxxPythonxxx"
print(s3.strip("x"))        # "Python"

s4 = "ABChelloCBA"
print(s4.strip("ABC"))      # "hello"  A/B/C 都會被去除

# ?? 常見誤區(qū)
s5 = "  Hello World  "
print(s5.strip())           # "Hello World"  只去兩端,中間空格保留!

s6 = "abchelloabc"
print(s6.strip("abc"))      # "hello"  不是去子串"abc",是去 a/b/c 三個字符

# ========== 實際應用 ==========
# 讀取用戶輸入時幾乎總要 strip
user_input = input("請輸入: ").strip()

# 清洗 CSV 數據
raw_fields = ["  Alice  ", " 28 ", " Beijing "]
clean = [f.strip() for f in raw_fields]  # ['Alice', '28', 'Beijing']

3.5 編碼與解碼:encode / decode

# ========== encode: str → bytes ==========
s = "你好,Python"
print(type(s))               # <class 'str'>

b_utf8 = s.encode("utf-8")   # UTF-8 編碼(推薦 ?)
b_gbk = s.encode("gbk")      # GBK 編碼(中文 Windows 常見)
print(b_utf8)                # b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8cPython'
print(b_gbk)                 # b'\xc4\xe3\xba\xc3\xa3\xacPython'

# ========== decode: bytes → str ==========
print(b_utf8.decode("utf-8"))   # "你好,Python"
print(b_gbk.decode("gbk"))      # "你好,Python"

# ?? 編解碼必須一致,否則亂碼或報錯
# b_utf8.decode("gbk")          # UnicodeDecodeError 或亂碼!

# ========== 錯誤處理策略 ==========
bad_bytes = b"\xff\xfe invalid"
print(bad_bytes.decode("utf-8", errors="ignore"))    # " invalid"  忽略錯誤字節(jié)
print(bad_bytes.decode("utf-8", errors="replace"))    # "?? invalid" 替換為?
print(bad_bytes.decode("utf-8", errors="backslashreplace"))  # "\\xff\\xfe invalid"

# ========== 常用場景 ==========
# 1. 網絡傳輸
data = "Hello".encode("utf-8")   # 發(fā)送前編碼
msg = data.decode("utf-8")       # 接收后解碼

# 2. 文件讀寫
with open("test.txt", "w", encoding="utf-8") as f:  # 指定編碼
    f.write("你好")

# 3. 判斷編碼
import chardet
raw = "你好".encode("gbk")
result = chardet.detect(raw)      # {'encoding': 'GB2312', 'confidence': 0.99, ...}

3.6 其他常用方法速查

s = "Hello, Python!"

# ========== 大小寫 ==========
print(s.upper())          # "HELLO, PYTHON!"     全大寫
print(s.lower())          # "hello, python!"      全小寫
print(s.title())          # "Hello, Python!"      每個單詞首字母大寫
print(s.capitalize())     # "Hello, python!"      僅首字母大寫
print(s.swapcase())       # "hELLO, pYTHON!"      大小寫互換

# ========== 判斷類 ==========
print("123".isdigit())        # True   是否全是數字
print("abc".isalpha())        # True   是否全是字母
print("abc123".isalnum())     # True   是否全是字母或數字
print("   ".isspace())        # True   是否全是空白
print("Hello".isupper())      # False  是否全大寫
print("hello".islower())      # True   是否全小寫
print("Hello World".istitle()) # True  是否標題格式

# ========== 填充對齊 ==========
print("Python".center(20, "-"))    # "-------Python-------"
print("Python".ljust(20, "-"))     # "Python--------------"
print("Python".rjust(20, "-"))     # "--------------Python"
print("42".zfill(6))               # "000042"  左補零(處理編號常用)

# ========== 前綴后綴 ==========
print("test.py".startswith("test"))   # True
print("test.py".endswith(".py"))      # True
# 支持元組參數
print("test.py".endswith((".py", ".txt")))   # True

# ========== 判斷包含 ==========
print("Python" in "I love Python")   # True   推薦方式 ?
print("Java" not in "I love Python") # True

4. 正則表達式入門:re 模塊核心 API

4.1 正則表達式是什么?

正則表達式(Regular Expression,簡稱 regex)是一種模式匹配語言,用于在文本中搜索、匹配、替換符合特定規(guī)則的字符串。

普通字符串查找:  "error" in log        → 只能找固定文本
正則表達式查找:  re.search(r"error\d+", log)  → 能找 error42、error007 等模式

4.2 核心元字符速查表

元字符含義示例匹配
.任意單個字符(除換行)a.cabc, a1c, a c
^行首^Hello行首的 Hello
$行尾world$行尾的 world
*前一項 0 次或多次ab*cac, abc, abbc
+前一項 1 次或多次ab+cabc, abbc
?前一項 0 次或 1 次ab?cac, abc
{n}前一項恰好 n 次\d{3}123
{n,m}前一項 n 到 m 次\d{2,4}12, 123, 1234
[]字符集[aeiou]a, e, i, o, u
[^]取反字符集[^0-9]非數字
()分組(捕獲)(ab)+ab, abab
|cat|dogcat 或 dog
\d數字 [0-9]\d+42, 007
\w單詞字符 [a-zA-Z0-9_]\w+hello_42
\s空白字符\s+空格/Tab/換行
\D非數字\D+abc
\W非單詞字符\W+!@#
\S非空白\S+非空白序列

4.3 re 模塊六大核心 API

import re

text = "My phone is 138-1234-5678 and office is 010-8765-4321"

# ========== ? re.search() —— 搜索第一個匹配 ==========
# 掃描整個字符串,返回第一個匹配的 Match 對象或 None
match = re.search(r"\d{3}-\d{4}-\d{4}", text)
if match:
    print(f"找到: {match.group()}")     # 138-1234-5678
    print(f"位置: {match.start()}-{match.end()}")  # 位置: 12-27
    print(f"span: {match.span()}")      # (12, 27)

# ========== ? re.match() —— 只匹配字符串開頭 ==========
# 僅在字符串開頭匹配,開頭不匹配則返回 None
result1 = re.match(r"My", text)          # ? 匹配成功
result2 = re.match(r"phone", text)       # None,不在開頭
# 實際開發(fā)中更推薦用 search + ^ 代替 match
result3 = re.search(r"^My", text)        # 等價于 match

# ========== ? re.findall() —— 找出所有匹配,返回列表 ==========
phones = re.findall(r"\d{3}-\d{4}-\d{4}", text)
print(phones)   # ['138-1234-5678', '010-8765-4321']

# 帶分組的 findall —— 返回分組內容的元組列表
pattern = r"(\d{3})-(\d{4})-(\d{4})"
groups = re.findall(pattern, text)
print(groups)   # [('138', '1234', '5678'), ('010', '8765', '4321')]

# ========== ? re.finditer() —— 迭代器版 findall ==========
# 返回迭代器,每個元素是 Match 對象(比 findall 更節(jié)省內存)
for m in re.finditer(r"\d{3}-\d{4}-\d{4}", text):
    print(f"Phone: {m.group()}, Position: {m.span()}")

# ========== ? re.sub() —— 替換 ==========
# re.sub(pattern, replacement, string, count=0)
# 隱藏手機號中間四位
hidden = re.sub(r"(\d{3})-\d{4}-(\d{4})", r"\1-****-\2", text)
print(hidden)   # My phone is 138-****-5678 and office is 010-****-4321

# 使用函數作為 replacement
def mask_phone(match):
    return f"{match.group(1)}-****-{match.group(3)}"

hidden2 = re.sub(r"(\d{3})-(\d{4})-(\d{4})", mask_phone, text)

# ========== ? re.split() —— 正則分割 ==========
# 按多種分隔符分割
data = "one,two;three|four"
result = re.split(r"[,;|]", data)
print(result)   # ['one', 'two', 'three', 'four']

# 帶捕獲組的 split —— 分隔符也會出現在結果中
result2 = re.split(r"([,;|])", data)
print(result2)  # ['one', ',', 'two', ';', 'three', '|', 'four']

4.4 Match 對象常用方法

import re

text = "Order #12345, total: $99.50"
match = re.search(r"Order #(\d+), total: \$(\d+\.\d+)", text)

if match:
    match.group()        # 'Order #12345, total: $99.50'  完整匹配
    match.group(0)       # 同上,0 = 整體匹配
    match.group(1)       # '12345'  第1個分組
    match.group(2)       # '99.50'  第2個分組
    match.groups()       # ('12345', '99.50')  所有分組元組
    match.start()        # 0   匹配起始位置
    match.end()          # 29  匹配結束位置
    match.span()         # (0, 29)  匹配范圍

    # 命名分組(更可讀)
    match2 = re.search(r"Order #(?P<id>\d+), total: \$(?P<amount>\d+\.\d+)", text)
    match2.group("id")       # '12345'
    match2.group("amount")   # '99.50'
    match2.groupdict()       # {'id': '12345', 'amount': '99.50'}

4.5 編譯正則:re.compile

當同一個正則需要反復使用時,預編譯可以提升性能:

import re

# ========== 預編譯 ==========
phone_pattern = re.compile(r"(\d{3})-(\d{4})-(\d{4})")

# 之后直接用編譯好的對象調用方法
text1 = "Call 138-1234-5678"
text2 = "Fax 010-8765-4321"

match1 = phone_pattern.search(text1)
match2 = phone_pattern.search(text2)

# 編譯時可以加標志位
case_insensitive = re.compile(r"hello", re.IGNORECASE)  # 忽略大小寫
multiline_mode = re.compile(r"^hello", re.MULTILINE)     # ^ 匹配每行行首
dotall_mode = re.compile(r"hello.world", re.DOTALL)      # . 匹配換行符

# 常用標志位
# re.IGNORECASE / re.I   忽略大小寫
# re.MULTILINE / re.M    ^ 和 $ 匹配每行
# re.DOTALL / re.S       . 匹配換行符
# re.VERBOSE / re.X      允許寫注釋(復雜正則推薦)

VERBOSE 模式——讓復雜正則可讀:

import re

# 普通寫法:難以閱讀
pattern1 = r"(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})\.(?P<ms>\d{3})"

# VERBOSE 寫法:清晰明了 ?
pattern2 = re.compile(r"""
    (?P<hour>\d{2})      # 時:2位數字
    :                    # 分隔符
    (?P<min>\d{2})       # 分:2位數字
    :                    # 分隔符
    (?P<sec>\d{2})       # 秒:2位數字
    \.                   # 小數點
    (?P<ms>\d{3})        # 毫秒:3位數字
""", re.VERBOSE)

time_text = "14:30:25.123"
match = pattern2.search(time_text)
print(match.groupdict())  # {'hour': '14', 'min': '30', 'sec': '25', 'ms': '123'}

4.6 貪婪 vs 非貪婪

import re

html = "<div>Hello</div><div>World</div>"

# ========== 貪婪匹配(默認) ==========
# .* 和 .+ 會盡可能多地匹配
greedy = re.findall(r"<div>.*</div>", html)
print(greedy)   # ['<div>Hello</div><div>World</div>']  匹配了整個!??

# ========== 非貪婪匹配(加 ?) ==========
# .*? 和 .+? 會盡可能少地匹配
non_greedy = re.findall(r"<div>.*?</div>", html)
print(non_greedy)  # ['<div>Hello</div>', '<div>World</div>']  ? 兩個獨立匹配

# 規(guī)則總結:
# 貪婪:  *   +   ?   {n,m}    → 盡量多匹配
# 非貪婪:*?  +?  ??  {n,m}?   → 盡量少匹配

4.7 常用正則模式速查

import re

# 郵箱
email_re = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"

# 手機號(中國大陸)
phone_re = r"1[3-9]\d{9}"

# IP 地址
ip_re = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"

# URL
url_re = r"https?://[^\s<>\"']+\.[a-zA-Z]{2,}"

# 日期 YYYY-MM-DD
date_re = r"\d{4}-\d{2}-\d{2}"

# 身份證號(18位)
id_re = r"\d{17}[\dXx]"

# 中文字符
chinese_re = r"[\u4e00-\u9fa5]+"

# 快速驗證
test_email = "user@example.com"
print(bool(re.fullmatch(email_re, test_email)))  # True

5. 字節(jié)串 bytes vs 字符串 str 詳解

5.1 本質區(qū)別

┌──────────────────────────────────────────────────┐
│                    str (字符串)                     │
│  - 存儲的是 Unicode 碼點(抽象字符)                │
│  - 人能看懂的文本                                   │
│  - Python 3 中所有字符串默認是 str                  │
│  - 示例: "你好"                                    │
├──────────────────────────────────────────────────┤
│                   bytes (字節(jié)串)                    │
│  - 存儲的是原始字節(jié)(0~255 的整數序列)             │
│  - 機器能看懂的二進制數據                           │
│  - 網絡傳輸、文件存儲、編解碼的中間形態(tài)              │
│  - 示例: b'\xe4\xbd\xa0\xe5\xa5\xbd'              │
└──────────────────────────────────────────────────┘

轉換關系:
  encode()                    decode()
  str ──────────→ bytes ──────────→ str
       編碼            解碼

5.2 創(chuàng)建方式對比

# ========== str 創(chuàng)建 ==========
s1 = "Hello"              # 普通字符串
s2 = '你好'               # Unicode 字符串
s3 = """多行
字符串"""                  # 多行字符串

# ========== bytes 創(chuàng)建 ==========
b1 = b"Hello"             # 字節(jié)串字面量(只支持 ASCII 字符)
b2 = b'\x48\x65\x6c\x6c\x6f'  # 十六進制表示
b3 = bytes([72, 101, 108, 108, 111])  # 從整數列表創(chuàng)建
b4 = "你好".encode("utf-8")    # 從字符串編碼

# ?? bytes 字面量只能包含 ASCII 字符
# b"你好"               # SyntaxError!
# 必須通過 encode 創(chuàng)建含中文的 bytes

# ========== bytearray(可變字節(jié)串) ==========
ba = bytearray(b"Hello")
ba[0] = 74               # 可修改!bytearray 是可變的
print(ba)                 # bytearray(b'Jello')

5.3 操作對比

s = "Hello"
b = b"Hello"

# ========== 相同的操作 ==========
print(len(s), len(b))          # 5 5
print(s[0], b[0])              # H 72  ?? str 索引返回字符,bytes 索引返回整數!
print(s[1:3], b[1:3])          # el b'el'  切片都返回同類型
print(s + " World", b + b" World")  # 拼接
print(s * 2, b * 2)            # 重復

# ========== 不同的操作 ==========
# 索引類型不同
print(type(s[0]))    # <class 'str'>
print(type(b[0]))    # <class 'int'>   ?? 關鍵區(qū)別!

# 遍歷
for ch in "ABC":
    print(ch)         # A  B  C     → 字符

for byte in b"ABC":
    print(byte)       # 65 66 67    → 整數

# 包含判斷
print("H" in "Hello")     # True   str 中判斷字符
print(72 in b"Hello")     # True   bytes 中判斷整數
print(b"H" in b"Hello")   # True   bytes 中也可以判斷字節(jié)串

# ?? 不能混合操作
# "Hello" + b" World"     # TypeError!
# "Hello" == b"Hello"     # False  類型不同,永不相等

5.4 編碼深入:UTF-8 vs GBK vs ASCII

text = "你好A"

# ========== 不同編碼對比 ==========
utf8_bytes = text.encode("utf-8")    # b'\xe4\xbd\xa0\xe5\xa5\xbdA'  6字節(jié)
gbk_bytes = text.encode("gbk")       # b'\xc4\xe3\xba\xc3A'          5字節(jié)

print(f"UTF-8: {utf8_bytes}  長度: {len(utf8_bytes)}")
print(f"GBK:   {gbk_bytes}  長度: {len(gbk_bytes)}")

# 編碼規(guī)則:
# UTF-8: 中文3字節(jié),ASCII 1字節(jié)(變長編碼,互聯網標準)?
# GBK:   中文2字節(jié),ASCII 1字節(jié)(中文 Windows 傳統(tǒng)編碼)
# ASCII: 只支持英文,1字節(jié)(0-127)

# ========== 查看字符的 Unicode 碼點 ==========
print(ord("你"))       # 20320   Unicode 碼點
print(ord("A"))        # 65
print(chr(20320))      # "你"    碼點轉字符
print(chr(65))         # "A"

# ========== 實際場景 ==========
# 場景1:判斷文件編碼
def detect_file_encoding(filepath):
    """檢測文件編碼并讀取"""
    with open(filepath, "rb") as f:       # 二進制模式讀取
        raw = f.read(4096)                 # 讀取前4KB
    import chardet
    result = chardet.detect(raw)
    encoding = result["encoding"]
    with open(filepath, "r", encoding=encoding) as f:
        return f.read()

# 場景2:網絡數據
import json
data = {"name": "yance", "msg": "你好"}
json_bytes = json.dumps(data, ensure_ascii=False).encode("utf-8")
# 發(fā)送 json_bytes 到網絡...
received = json_bytes.decode("utf-8")
parsed = json.loads(received)

# 場景3:大小計算
msg = "Hello你好"
print(f"字符數: {len(msg)}")                    # 7  (5個英文字母 + 2個中文字)
print(f"UTF-8 字節(jié)數: {len(msg.encode('utf-8'))}")  # 11 (5×1 + 2×3)
print(f"GBK 字節(jié)數: {len(msg.encode('gbk'))}")      # 9  (5×1 + 2×2)

5.5 str / bytes / bytearray 速查對比

特性strbytesbytearray
可變性? 不可變? 不可變? 可變
字面量"hello"b"hello"
索引返回str (字符)int (0-255)int (0-255)
中文支持?? (需編碼)? (需編碼)
編碼方法.encode().decode().decode()
網絡傳輸? 需編碼??
字典 key??? (不可哈希)
典型場景文本處理網絡I/O、文件I/O需修改的二進制數據

6. 實操 Demo:日志解析器(正則實戰(zhàn))

6.1 需求描述

給定一段 Nginx 風格的訪問日志,要求解析出每條日志的結構化數據:

192.168.1.100 - - [30/May/2026:10:15:30 +0800] "GET /api/users HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
10.0.0.1 - admin [30/May/2026:10:16:45 +0800] "POST /api/login HTTP/1.1" 401 56 "-" "curl/7.68.0"
172.16.0.50 - - [30/May/2026:10:17:12 +0800] "GET /static/logo.png HTTP/1.1" 304 0 "https://example.com/home" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"

需要提取:IP、用戶、時間、請求方法、請求路徑、協(xié)議、狀態(tài)碼、響應大小、來源頁、UA。

6.2 完整實現

"""
日志解析器 —— Python 字符串與正則實戰(zhàn)
功能:解析 Nginx 訪問日志,生成統(tǒng)計報告
"""

import re
from collections import Counter, defaultdict
from dataclasses import dataclass, field
from typing import Optional


# ==================== 數據模型 ====================

@dataclass
class LogEntry:
    """單條日志記錄"""
    ip: str
    user: str
    datetime: str
    method: str
    path: str
    protocol: str
    status: int
    size: int
    referer: str
    user_agent: str


@dataclass
class LogReport:
    """日志統(tǒng)計報告"""
    total_requests: int = 0
    status_counter: Counter = field(default_factory=Counter)
    method_counter: Counter = field(default_factory=Counter)
    ip_counter: Counter = field(default_factory=Counter)
    path_counter: Counter = field(default_factory=Counter)
    total_bytes: int = 0
    entries: list = field(default_factory=list)


# ==================== 正則模式 ====================

# 使用 VERBOSE 模式,讓正則可讀
NGINX_LOG_PATTERN = re.compile(r"""
    ^(?P<ip>\S+)                    # IP 地址
    \s+-\s+                         # 分隔符: -
    (?P<user>\S+)                   # 用戶(- 表示匿名)
    \s+\[                           # 分隔符: [
    (?P<datetime>[^\]]+)            # 時間:30/May/2026:10:15:30 +0800
    \]\s+"                          # 分隔符: ] "
    (?P<method>GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)  # 請求方法
    \s+                             # 空格
    (?P<path>\S+)                   # 請求路徑
    \s+                             # 空格
    (?P<protocol>HTTP/[\d.]+)       # 協(xié)議版本
    "\s+                            # 分隔符: "
    (?P<status>\d{3})               # 狀態(tài)碼
    \s+                             # 空格
    (?P<size>\d+)                   # 響應大小
    \s+"                            # 分隔符: "
    (?P<referer>[^"]*)              # 來源頁
    "\s+"                           # 分隔符: " "
    (?P<user_agent>[^"]*)           # User-Agent
    ".*$                            # 結尾
""", re.VERBOSE)


# ==================== 解析器 ====================

class LogParser:
    """Nginx 日志解析器"""

    def __init__(self, pattern: re.Pattern = NGINX_LOG_PATTERN):
        self.pattern = pattern

    def parse_line(self, line: str) -> Optional[LogEntry]:
        """解析單行日志"""
        line = line.strip()
        if not line:
            return None

        match = self.pattern.match(line)
        if not match:
            print(f"[WARN] 無法解析: {line[:80]}...")
            return None

        d = match.groupdict()
        return LogEntry(
            ip=d["ip"],
            user=d["user"] if d["user"] != "-" else "anonymous",
            datetime=d["datetime"],
            method=d["method"],
            path=d["path"],
            protocol=d["protocol"],
            status=int(d["status"]),
            size=int(d["size"]),
            referer=d["referer"] if d["referer"] != "-" else "",
            user_agent=d["user_agent"],
        )

    def parse_file(self, filepath: str) -> LogReport:
        """解析日志文件"""
        report = LogReport()

        with open(filepath, "r", encoding="utf-8") as f:
            for line in f:
                entry = self.parse_line(line)
                if entry:
                    report.entries.append(entry)
                    report.total_requests += 1
                    report.status_counter[entry.status] += 1
                    report.method_counter[entry.method] += 1
                    report.ip_counter[entry.ip] += 1
                    report.path_counter[entry.path] += 1
                    report.total_bytes += entry.size

        return report

    def parse_string(self, log_text: str) -> LogReport:
        """解析日志字符串(用于測試)"""
        report = LogReport()

        for line in log_text.strip().split("\n"):
            entry = self.parse_line(line)
            if entry:
                report.entries.append(entry)
                report.total_requests += 1
                report.status_counter[entry.status] += 1
                report.method_counter[entry.method] += 1
                report.ip_counter[entry.ip] += 1
                report.path_counter[entry.path] += 1
                report.total_bytes += entry.size

        return report


# ==================== 報告生成 ====================

class ReportPrinter:
    """格式化輸出統(tǒng)計報告"""

    @staticmethod
    def print_report(report: LogReport):
        """輸出完整報告"""
        print("=" * 60)
        print("?? Nginx 日志分析報告")
        print("=" * 60)

        # 總覽
        print(f"\n?? 總覽")
        print(f"  總請求數:   {report.total_requests}")
        print(f"  總流量:     {report.total_bytes:,} bytes "
              f"({report.total_bytes / 1024:.1f} KB)")

        # 狀態(tài)碼分布
        print(f"\n?? 狀態(tài)碼分布")
        for status, count in report.status_counter.most_common():
            bar = "█" * (count * 40 // report.total_requests)
            print(f"  {status}: {count:>4}  {bar}")

        # 請求方法分布
        print(f"\n?? 請求方法分布")
        for method, count in report.method_counter.most_common():
            print(f"  {method:<8}: {count}")

        # TOP 5 IP
        print(f"\n?? TOP 5 訪問 IP")
        for ip, count in report.ip_counter.most_common(5):
            print(f"  {ip:<18}: {count} 次")

        # TOP 5 路徑
        print(f"\n?? TOP 5 訪問路徑")
        for path, count in report.path_counter.most_common(5):
            print(f"  {path:<30}: {count} 次")

        print("\n" + "=" * 60)

    @staticmethod
    def search_entries(report: LogReport, **kwargs) -> list[LogEntry]:
        """按條件篩選日志條目"""
        results = report.entries
        for key, value in kwargs.items():
            results = [e for e in results if getattr(e, key) == value]
        return results


# ==================== 主程序 ====================

def main():
    """主函數:演示完整流程"""

    # 模擬日志數據
    sample_log = """
192.168.1.100 - - [30/May/2026:10:15:30 +0800] "GET /api/users HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
10.0.0.1 - admin [30/May/2026:10:16:45 +0800] "POST /api/login HTTP/1.1" 401 56 "-" "curl/7.68.0"
172.16.0.50 - - [30/May/2026:10:17:12 +0800] "GET /static/logo.png HTTP/1.1" 304 0 "https://example.com/home" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
192.168.1.100 - - [30/May/2026:10:18:00 +0800] "GET /api/users HTTP/1.1" 200 2456 "https://example.com/users" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
10.0.0.1 - admin [30/May/2026:10:18:30 +0800] "POST /api/login HTTP/1.1" 200 234 "-" "curl/7.68.0"
192.168.1.200 - - [30/May/2026:10:19:05 +0800] "DELETE /api/users/5 HTTP/1.1" 403 89 "https://example.com/admin" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
172.16.0.50 - - [30/May/2026:10:19:30 +0800] "GET /static/style.css HTTP/1.1" 200 8765 "https://example.com/home" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
192.168.1.100 - - [30/May/2026:10:20:00 +0800] "PUT /api/users/1 HTTP/1.1" 200 567 "https://example.com/users/1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
10.0.0.2 - - [30/May/2026:10:20:15 +0800] "GET /api/products HTTP/1.1" 200 4532 "https://example.com/shop" "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X)"
192.168.1.100 - - [30/May/2026:10:21:00 +0800] "GET /api/users HTTP/1.1" 500 120 "https://example.com/users" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
"""

    # 1. 解析日志
    parser = LogParser()
    report = parser.parse_string(sample_log)

    # 2. 輸出報告
    ReportPrinter.print_report(report)

    # 3. 條件篩選示例
    print("\n?? 篩選示例:狀態(tài)碼為 200 的請求")
    success_entries = ReportPrinter.search_entries(report, status=200)
    for entry in success_entries:
        print(f"  {entry.ip} → {entry.method} {entry.path} ({entry.status})")

    print("\n?? 篩選示例:來自 192.168.1.100 的請求")
    ip_entries = ReportPrinter.search_entries(report, ip="192.168.1.100")
    for entry in ip_entries:
        print(f"  {entry.method} {entry.path} → {entry.status}")

    # 4. 字符串操作技巧演示
    print("\n" + "=" * 60)
    print("?? 日志解析中用到的字符串技巧")
    print("=" * 60)

    line = '192.168.1.100 - - [30/May/2026:10:15:30 +0800] "GET /api/users HTTP/1.1" 200 1234'

    # 技巧1:split 快速提取
    ip = line.split()[0]
    print(f"split 取 IP: {ip}")

    # 技巧2:strip 去除引號
    raw_request = '"GET /api/users HTTP/1.1"'
    request = raw_request.strip('"')
    print(f"strip 去引號: {request}")

    # 技巧3:正則命名分組提取
    time_match = re.search(r"\[(?P<time>[^\]]+)\]", line)
    if time_match:
        print(f"正則提時間: {time_match.group('time')}")

    # 技巧4:f-string 格式化輸出
    status = 200
    size = 1234
    print(f"格式化輸出: status={status:03d}, size={size:,} bytes")

    # 技巧5:join 拼接路徑
    segments = ["api", "v2", "users", "123"]
    url_path = "/" + "/".join(segments)
    print(f"join 拼路徑: {url_path}")


if __name__ == "__main__":
    main()

6.3 運行結果

============================================================
?? Nginx 日志分析報告
============================================================

?? 總覽
  總請求數:   10
  總流量:     18,053 bytes (17.6 KB)

?? 狀態(tài)碼分布
  200:    6  ████████████████████████
  401:    1  ████
  304:    1  ████
  403:    1  ████
  500:    1  ████

?? 請求方法分布
  GET     : 6
  POST    : 2
  PUT     : 1
  DELETE  : 1

?? TOP 5 訪問 IP
  192.168.1.100     : 4 次
  10.0.0.1          : 2 次
  172.16.0.50       : 2 次
  192.168.1.200     : 1 次
  10.0.0.2          : 1 次

?? TOP 5 訪問路徑
  /api/users               : 3 次
  /api/login               : 2 次
  /static/logo.png         : 1 次
  /static/style.css        : 1 次
  /api/users/5             : 1 次

============================================================

?? 篩選示例:狀態(tài)碼為 200 的請求
  192.168.1.100 → GET /api/users (200)
  192.168.1.100 → GET /api/users (200)
  10.0.0.1 → POST /api/login (200)
  172.16.0.50 → GET /static/style.css (200)
  192.168.1.100 → PUT /api/users/1 (200)
  10.0.0.2 → GET /api/products (200)

?? 篩選示例:來自 192.168.1.100 的請求
  GET /api/users → 200
  GET /api/users → 200
  PUT /api/users/1 → 200
  GET /api/users → 500

?? 日志解析中用到的字符串技巧
============================================================
split 取 IP: 192.168.1.100
strip 去引號: GET /api/users HTTP/1.1
正則提時間: 30/May/2026:10:15:30 +0800
格式化輸出: status=200, size=1,234 bytes
join 拼路徑: /api/v2/users/123

7. 總結與速查表

7.1 字符串方法速查

分類方法說明示例
查找find()返回索引或 -1"hello".find("ll") → 2
index()返回索引或異常"hello".index("ll") → 2
count()出現次數"hello".count("l") → 2
替換replace()替換子串"aabb".replace("a","x") → “xxbb”
分割split()分割為列表"a,b,c".split(",") → [‘a’,‘b’,‘c’]
rsplit()從右分割"a-b-c".rsplit("-",1) → [‘a-b’,‘c’]
splitlines()按行分割"a\nb".splitlines() → [‘a’,‘b’]
join()合并為字符串",".join(['a','b']) → “a,b”
去除strip()去兩端字符" hi ".strip() → “hi”
lstrip()去左端" hi ".lstrip() → "hi "
rstrip()去右端" hi ".rstrip() → " hi"
大小寫upper()全大寫"Hi".upper() → “HI”
lower()全小寫"Hi".lower() → “hi”
title()標題格式"hi world".title() → “Hi World”
capitalize()首字母大寫"hi".capitalize() → “Hi”
swapcase()大小寫互換"Hi".swapcase() → “hI”
判斷startswith()前綴判斷"test.py".startswith("test") → True
endswith()后綴判斷"test.py".endswith(".py") → True
isdigit()全是數字"123".isdigit() → True
isalpha()全是字母"abc".isalpha() → True
isalnum()字母或數字"abc123".isalnum() → True
對齊center()居中"hi".center(6) → " hi "
ljust()左對齊"hi".ljust(6) → "hi "
rjust()右對齊"hi".rjust(6) → " hi"
zfill()左補零"42".zfill(5) → “00042”
編解碼encode()str→bytes"你好".encode("utf-8")
decode()bytes→strb'\xe4...'.decode("utf-8")

7.2 re 模塊 API 速查

API功能返回值
re.search(pattern, string)搜索第一個匹配Match 或 None
re.match(pattern, string)匹配字符串開頭Match 或 None
re.fullmatch(pattern, string)完整匹配整個字符串Match 或 None
re.findall(pattern, string)找出所有匹配列表
re.finditer(pattern, string)迭代器版 findall迭代器
re.sub(pattern, repl, string)替換新字符串
re.split(pattern, string)正則分割列表
re.compile(pattern)預編譯正則Pattern 對象

7.3 關鍵要點回顧

  1. 字符串不可變:所有"修改"操作都返回新字符串,原串不變
  2. 切片左閉右開s[2:5] 取索引 2、3、4,不取 5
  3. f-string 首選:可讀性好、性能優(yōu)、功能強(3.6+)
  4. 原始字符串 r"":正則和 Windows 路徑必備,避免轉義地獄
  5. bytes vs str:網絡 I/O 用 bytes,文本處理用 str,encode/decode 橋接
  6. 正則 VERBOSE:復雜正則一定要用 re.VERBOSE,可讀性 >> 簡潔性
  7. 非貪婪模式.*? 是 HTML/XML 提取的標配
  8. 預編譯:同一正則反復使用時,re.compile() 提升性能

以上就是Python字符串從入門到精通的實戰(zhàn)指南的詳細內容,更多關于Python字符串指南的資料請關注腳本之家其它相關文章!

相關文章

  • PyTorch 如何設置隨機數種子使結果可復現

    PyTorch 如何設置隨機數種子使結果可復現

    這篇文章主要介紹了PyTorch 設置隨機數種子使結果可復現操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • 利用python畫出AUC曲線的實例

    利用python畫出AUC曲線的實例

    今天小編就為大家分享一篇利用python畫出AUC曲線的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • 如何基于Python和Flask編寫Prometheus監(jiān)控

    如何基于Python和Flask編寫Prometheus監(jiān)控

    這篇文章主要介紹了如何基于Python和Flask編寫Prometheus監(jiān)控,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • pycharm無法導入本地模塊的解決方式

    pycharm無法導入本地模塊的解決方式

    今天小編就為大家分享一篇pycharm無法導入本地模塊的解決方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • Python break語句詳解

    Python break語句詳解

    這篇文章主要介紹了Python break語句的作用、使用方法,需要的朋友可以參考下
    2014-03-03
  • Python數據結構之遞歸方法詳解

    Python數據結構之遞歸方法詳解

    這篇文章主要為大家介紹了遞歸的基本概念以及如何構建遞歸程序。通過本章的學習,大家可以理解遞歸的基本概念,了解遞歸背后蘊含的編程思想以及掌握構建遞歸程序的方法,需要的可以參考一下
    2022-04-04
  • 基于python分析你的上網行為 看看你平時上網都在干嘛

    基于python分析你的上網行為 看看你平時上網都在干嘛

    這篇文章主要介紹了基于python分析你的上網行為 看看你平時上網都在干嘛,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • Python實現XML文件解析的示例代碼

    Python實現XML文件解析的示例代碼

    本篇文章主要介紹了Python實現XML文件解析的示例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Python連接數據庫使用matplotlib畫柱形圖

    Python連接數據庫使用matplotlib畫柱形圖

    這篇文章主要介紹了Python連接數據庫使用matplotlib畫柱形圖,文章通過實例展開對主題的相關介紹。具有一定的知識參考價值性,感興趣的小伙伴可以參考一下
    2022-06-06
  • python圖書管理系統(tǒng)

    python圖書管理系統(tǒng)

    這篇文章主要為大家詳細介紹了python圖書管理系統(tǒng)的實現代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03

最新評論

三门县| 论坛| 弋阳县| 亚东县| 南平市| 蚌埠市| 舟山市| 张家界市| 海口市| 天峻县| 桂平市| 乌恰县| 班戈县| 赞皇县| 湖北省| 肥东县| 南靖县| 池州市| 新沂市| 绍兴市| 红安县| 紫阳县| 区。| 连州市| 唐河县| 乌兰县| 钟山县| 江津市| 德江县| 清镇市| 东阳市| 民权县| 无棣县| 潜江市| 环江| 湖口县| 定襄县| 高密市| 民丰县| 察隅县| 保亭|