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

Python字符串相關(guān)操作及正則表達(dá)式學(xué)習(xí)教程

 更新時(shí)間:2026年03月06日 09:43:03   作者:藍(lán)桉~MLGT  
字符串的重要功能之一就是正則表達(dá)式,正則表達(dá)式在各種操作中都起到了關(guān)鍵作用,尤其是Python標(biāo)志性的功能爬蟲也是以這個(gè)語法為基礎(chǔ)建立的,這篇文章主要介紹了Python字符串相關(guān)操作及正則表達(dá)式的相關(guān)資料,需要的朋友可以參考下

一、字符串的常用方法

類別方法描述代碼示例
大小寫.upper()轉(zhuǎn)大寫"hi".upper() → "HI"
.lower()轉(zhuǎn)小寫"HI".lower() → "hi"
.title()單詞首字母大寫"hi there".title() → "Hi There"
搜索替換.find(x)查找子串位置"hi".find("i") → 1
.count(x)統(tǒng)計(jì)出現(xiàn)次數(shù)"hello".count("l") → 2
.replace(a,b)替換子串"ha".replace("a","i") → "hi"
字符串判斷.startswith(x)檢查前綴"hi".startswith("h") → True
.endswith(x)檢查后綴"hi".endswith("i") → True
.isalpha()是否全字母"hi".isalpha() → True
去除空白.strip()移除首尾空白" hi ".strip() → "hi"
分割連接.split()分割為列表"a b".split() → ['a','b']
.join(list)連接列表"-".join(['a','b']) → "a-b"
對(duì)齊.center(n)居中對(duì)齊"hi".center(4) → " hi "

1. 大小寫轉(zhuǎn)換

# 原始字符串
original_str = "hello World, Python3!"

# .upper(): 將所有字符轉(zhuǎn)換為大寫
print(original_str.upper())  # 輸出: HELLO WORLD, PYTHON3!

# .lower(): 將所有字符轉(zhuǎn)換為小寫  
print(original_str.lower())  # 輸出: hello world, python3!

# .capitalize(): 將字符串首字母大寫,其余小寫
print(original_str.capitalize())  # 輸出: Hello world, python3!

# .title(): 將每個(gè)單詞的首字母大寫
print(original_str.title())  # 輸出: Hello World, Python3!

# .swapcase(): 交換大小寫
print(original_str.swapcase())  # 輸出: HELLO wORLD, pYTHON3!

2. 搜索與替換

text = "I love Python. Python is awesome."

# .find(sub): 返回子串首次出現(xiàn)的索引,未找到返回-1
print(text.find("Python"))    # 輸出: 7
print(text.find("Java"))      # 輸出: -1

# .index(sub): 與find類似,但未找到時(shí)會(huì)報(bào)錯(cuò)
print(text.index("Python"))   # 輸出: 7
# print(text.index("Java"))   # 這會(huì)引發(fā)ValueError異常

# .count(sub): 統(tǒng)計(jì)子串出現(xiàn)次數(shù)
print(text.count("Python"))   # 輸出: 2

# .replace(old, new): 替換子串
print(text.replace("Python", "Java"))  # 輸出: I love Java. Java is awesome.

注意:慎重使用index()方法,如果沒有找到對(duì)應(yīng)的字符串會(huì)報(bào)錯(cuò)"ValueError"。

3. 字符串判斷

# .startswith(prefix): 檢查是否以指定前綴開頭
filename = "document.pdf"
print(filename.startswith("doc"))    # 輸出: True
print(filename.startswith("xls"))    # 輸出: False

# .endswith(suffix): 檢查是否以指定后綴結(jié)尾  
print(filename.endswith(".pdf"))     # 輸出: True
print(filename.endswith(".docx"))    # 輸出: False

# .isalpha(): 是否全是字母(中文也被認(rèn)為是字母)
print("Hello".isalpha())      # 輸出: True
print("Hello123".isalpha())   # 輸出: False
print("你好".isalpha())        # 輸出: True

# .isdigit(): 是否全是數(shù)字
print("123".isdigit())        # 輸出: True
print("12.3".isdigit())       # 輸出: False

# .isalnum(): 是否全是字母或數(shù)字
print("Hello123".isalnum())   # 輸出: True
print("Hello 123".isalnum())  # 輸出: False(包含空格)

# .isspace(): 是否全是空白字符
print("   ".isspace())        # 輸出: True
print("  x  ".isspace())      # 輸出: False

注意:isalpha方法是判斷全是字母的方法,但是中文也會(huì)被識(shí)別為字母。

5. 分割與連接

# .split(sep): 使用分隔符分割字符串
csv_data = "apple,banana,orange,grape"
print(csv_data.split(","))           # 輸出: ['apple', 'banana', 'orange', 'grape']

sentence = "I love programming"
print(sentence.split())              # 輸出: ['I', 'love', 'programming'](默認(rèn)按空格分割)

# .join(iterable): 將序列中的元素用指定字符串連接
fruits = ['apple', 'banana', 'orange']
print("-".join(fruits))              # 輸出: apple-banana-orange
print(" ".join(["Hello", "World"]))  # 輸出: Hello World

6. 對(duì)齊與格式化

對(duì)齊

text = "Python"

# .center(width): 居中對(duì)齊
print(f"'{text.center(10)}'")        # 輸出: '  Python  '

# .ljust(width): 左對(duì)齊
print(f"'{text.ljust(10)}'")         # 輸出: 'Python    '

# .rjust(width): 右對(duì)齊
print(f"'{text.rjust(10)}'")         # 輸出: '    Python'

# 可以指定填充字符
print(f"'{text.center(10, '*')}'")   # 輸出: '**Python**'

格式化

?? 格式化分為三種方式:

  • 占位符(不推薦
  • f-string
  • format
name = "Alice"
age = 25

# f-string (Python 3.6+ 推薦)
message = f"我叫{name},今年{age}歲"
print(message)  # 我叫Alice,今年25歲

# 表達(dá)式和格式化
price = 15.5
print(f"價(jià)格: {price:.2f}元")     # 價(jià)格: 15.50元
print(f"明年年齡: {age + 1}")      # 明年年齡: 26

# format()方法
template = "我叫{},今年{}歲".format(name, age)
named_template = "我叫{name},今年{age}歲".format(name=name, age=age)

# %操作符 (傳統(tǒng)方式,不推薦新項(xiàng)目使用)
old_style = "我叫%s,今年%d歲" % (name, age)

format詳細(xì)解釋

Python的format()方法通過格式說明符({}中的:后面部分)提供精細(xì)的格式控制。格式說明符的基本語法為:{[字段名]!轉(zhuǎn)換字符:格式說明},其中格式說明又包含[[填充]對(duì)齊][符號(hào)][#][0][寬度][分組選項(xiàng)][.精度][類型]。

基本用法回顧

# 位置參數(shù)
print("{} {}".format("Hello", "World"))      # 輸出: Hello World

# 關(guān)鍵字參數(shù)  
print("{name} is {age} years old".format(name="Alice", age=25))

# 混合使用
print("{0} scored {score} points".format("Bob", score=95))

# 訪問屬性或索引
data = {"x": 10, "y": 20}
print("x={0[x]}, y={0[y]}".format(data))

對(duì)齊與填充

text = "Python"

# 左對(duì)齊 <,默認(rèn)填充空格
print("|{:<10}|".format(text))      # 輸出: |Python    |

# 右對(duì)齊 >
print("|{:>10}|".format(text))      # 輸出: |    Python|

# 居中對(duì)齊 ^
print("|{:^10}|".format(text))      # 輸出: |  Python  |

# 指定填充字符(必須在對(duì)齊符號(hào)前)
print("|{:*^10}|".format(text))     # 輸出: |**Python**|
print("|{:=^10}|".format(text))     # 輸出: |==Python==|

數(shù)字格式:符號(hào)控制

num = 42
neg_num = -42

# +: 總是顯示符號(hào)(正數(shù)顯示+,負(fù)數(shù)顯示-)
print("{:+} {:+}".format(num, neg_num))    # 輸出: +42 -42

# -: 僅負(fù)數(shù)顯示符號(hào)(默認(rèn)行為)
print("{:-} {:-}".format(num, neg_num))    # 輸出: 42 -42

# 空格: 正數(shù)前加空格,負(fù)數(shù)前加負(fù)號(hào)
print("|{: }| |{: }|".format(num, neg_num)) # 輸出: | 42| |-42|

數(shù)字格式:寬度、精度與千位分隔符

price = 1234.5678

# 寬度和精度控制
print("|{:10.2f}|".format(price))          # 輸出: |   1234.57|

# 千位分隔符 ,
print("{:,}".format(1000000))              # 輸出: 1,000,000
print("{:,.2f}".format(1234567.89))        # 輸出: 1,234,567.89

# 組合使用
print("|{:>15,.2f}|".format(price))        # 輸出: |       1,234.57|

數(shù)字格式:進(jìn)制轉(zhuǎn)換

number = 255

# 十進(jìn)制 d
print("{:d}".format(number))               # 輸出: 255

# 二進(jìn)制 b(# 顯示前綴)
print("{:#b}".format(number))              # 輸出: 0b11111111

# 八進(jìn)制 o
print("{:#o}".format(number))              # 輸出: 0o377

# 十六進(jìn)制 x/X(大小寫控制十六進(jìn)制字符)
print("{:#x}".format(number))              # 輸出: 0xff
print("{:#X}".format(number))              # 輸出: 0xFF

精度控制與類型指定

import math

# 浮點(diǎn)數(shù)精度控制
pi = math.pi
print("{:.2f}".format(pi))                 # 輸出: 3.14
print("{:.4f}".format(pi))                 # 輸出: 3.1416

# 百分比顯示 %
print("{:.1%}".format(0.256))              # 輸出: 25.6%

# 科學(xué)計(jì)數(shù)法 e/E
print("{:.2e}".format(123456789))          # 輸出: 1.23e+08
print("{:.2E}".format(0.000012345))        # 輸出: 1.23E-05

# 一般格式 g/G(在浮點(diǎn)和科學(xué)計(jì)數(shù)法間自動(dòng)選擇)
print("{:.5g}".format(123.456789))         # 輸出: 123.46
print("{:.5g}".format(123456789))          # 輸出: 1.2346e+08

零填充與特殊格式

# 零填充(相當(dāng)于右對(duì)齊并用0填充)
print("{:05d}".format(42))                 # 輸出: 00042
print("{:08.2f}".format(3.14))             # 輸出: 00003.14

# 字符串截?cái)?
text = "Hello World"
print("{:.5}".format(text))                # 輸出: Hello

f-string擴(kuò)展,語法基本一致(不可忽視?。。。?/strong>

name = "Alice"
age = 25
price = 19.99

# 基本使用
print(f"Name: {name:>10}, Age: {age:03d}")

# 數(shù)字格式化
print(f"Price: ${price:.2f}")
print(f"Percentage: {0.256:.1%}")

# 嵌套表達(dá)式
print(f"Result: {age * price:,.2f}")

格式說明符完整語法表

類別組件符號(hào)作用示例
填充填充任意字符填充字符(需與對(duì)齊符配合){:*<10}
對(duì)齊對(duì)齊<左對(duì)齊{:<10}
>右對(duì)齊{:>10}
^居中對(duì)齊{:^10}
=數(shù)字符號(hào)后填充{:=10}
符號(hào)符號(hào)+總是顯示符號(hào){:+}
-僅負(fù)數(shù)顯示符號(hào){:-}
空格正數(shù)前加空格{: }
特殊特殊#顯示進(jìn)制前綴{:#x}
0零填充{:05}
寬度寬度數(shù)字最小字段寬度{:10}
分組分組,千位分隔符{:,}
精度精度.數(shù)字浮點(diǎn)數(shù)精度{:.2f}
類型類型s字符串{:s}
d十進(jìn)制整數(shù){:d}
b二進(jìn)制{:b}
o八進(jìn)制{:o}
x/X十六進(jìn)制{:x}
f/F浮點(diǎn)數(shù){:.2f}
e/E科學(xué)計(jì)數(shù)法{:.2e}
g/G通用格式{:.5g}
%百分比{:.1%}

二、字符串的編碼和解碼、常用的加密解密基礎(chǔ)

1. 編碼和解碼

1.1. 基本使用

# 字符串在Python內(nèi)部以Unicode形式存儲(chǔ)
text = "你好,世界!Hello World! ??"
print(f"原始字符串: {text}")
print(f"字符串類型: {type(text)}")

# 編碼:字符串 → 字節(jié)序列
# UTF-8編碼(最常用,兼容ASCII)
utf8_bytes = text.encode('utf-8')
print(f"UTF-8編碼: {utf8_bytes}")
print(f"編碼后類型: {type(utf8_bytes)}")

# GBK編碼(中文環(huán)境常用)
gbk_bytes = text.encode('gbk')
print(f"GBK編碼: {gbk_bytes}")

# 解碼:字節(jié)序列 → 字符串
# UTF-8解碼
decoded_utf8 = utf8_bytes.decode('utf-8')
print(f"UTF-8解碼: {decoded_utf8}")

# GBK解碼
decoded_gbk = gbk_bytes.decode('gbk')
print(f"GBK解碼: {decoded_gbk}")

# 編碼解碼不匹配會(huì)導(dǎo)致亂碼或錯(cuò)誤
try:
    wrong_decode = utf8_bytes.decode('gbk')
    print(f"錯(cuò)誤解碼嘗試: {wrong_decode}")
except UnicodeDecodeError as e:
    print(f"解碼錯(cuò)誤: {e}")

1.2. 常用編碼方式對(duì)比

def compare_encodings(text, encodings=None):
    """比較不同編碼方式的結(jié)果"""
    if encodings is None:
        encodings = ['utf-8', 'gbk', 'ascii', 'latin-1']
    print(f"\n原始文本: {text}")
    for encoding in encodings:
        try:
            encoded = text.encode(encoding)
            decoded = encoded.decode(encoding)
            print(f"{encoding:>8}: 字節(jié)數(shù)={len(encoded):2d}, 可逆={text == decoded}")
        except Exception as e:
            print(f"{encoding:>8}: 錯(cuò)誤 - {e}")

# 測(cè)試不同文本
compare_encodings("Hello World")
compare_encodings("你好世界")
compare_encodings("Special chars: ?, ?, 日本")
D:\env\pycharm\pythonProject\demo1\demo2.py 

原始文本: Hello World
   utf-8: 字節(jié)數(shù)=11, 可逆=True
     gbk: 字節(jié)數(shù)=11, 可逆=True
   ascii: 字節(jié)數(shù)=11, 可逆=True
 latin-1: 字節(jié)數(shù)=11, 可逆=True

原始文本: 你好世界
   utf-8: 字節(jié)數(shù)=12, 可逆=True
     gbk: 字節(jié)數(shù)= 8, 可逆=True
   ascii: 錯(cuò)誤 - 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
 latin-1: 錯(cuò)誤 - 'latin-1' codec can't encode characters in position 0-3: ordinal not in range(256)

原始文本: Special chars: ?, ?, 日本
   utf-8: 字節(jié)數(shù)=29, 可逆=True
     gbk: 錯(cuò)誤 - 'gbk' codec can't encode character '\xf1' in position 15: illegal multibyte sequence
   ascii: 錯(cuò)誤 - 'ascii' codec can't encode character '\xf1' in position 15: ordinal not in range(128)
 latin-1: 錯(cuò)誤 - 'latin-1' codec can't encode characters in position 21-22: ordinal not in range(256)

Process finished with exit code 0

上面的例子是用來比較不同編碼方式對(duì)不同字符的支持程序,經(jīng)過對(duì)比我們可以得出以下的結(jié)論。

  • UTF-8是最通用的編碼,支持所有字符集

  • GBK對(duì)中文更高效但兼容性有限

  • ASCII/Latin-1適用范圍有限,只能處理有限字符集

1.3. 基于chardet庫的編碼解碼最佳示例

import chardet  
# 需要安裝: pip install chardet
# 直接在控制臺(tái)使用該命令安裝即可

def improved_smart_decode(byte_data):
    detection = chardet.detect(byte_data)
    encoding = detection['encoding']
    confidence = detection['confidence']

    print(f"檢測(cè)結(jié)果: {encoding}, 置信度: {confidence:.2f}")

    # 添加置信度閾值
    if encoding and confidence > 0.6:
        try:
            return byte_data.decode(encoding)
        except UnicodeDecodeError:
            pass
    print(f"檢測(cè)結(jié)果不可信,通常小于0.3視為完全不符合,小于0.6可信但不準(zhǔn)確,當(dāng)前置信度為:{confidence:^6.2f}不可信")
    print("基于常見的編碼方式進(jìn)行解碼...")
    # 回退方案:嘗試常見編碼
    for enc in ['utf-8', 'gbk', 'gb2312', 'latin-1']:
        try:
            new_result = byte_data.decode(enc)
            print(f"正確的編碼方式為:{enc}")
            return new_result
        except UnicodeDecodeError:
            continue

    return byte_data.decode('utf-8', errors='replace')


# 測(cè)試智能解碼
test_bytes = "你好世界".encode('gbk')
result = improved_smart_decode(test_bytes)
print(f"智能解碼結(jié)果: {result}")

輸出結(jié)果為:

D:\env\pycharm\pythonProject\demo1\demo2.py 

檢測(cè)結(jié)果: TIS-620, 置信度: 0.27
檢測(cè)結(jié)果不可信,通常小于0.3視為完全不符合,小于0.6可信但不準(zhǔn)確,當(dāng)前置信度為: 0.27 不可信
基于常見的編碼方式進(jìn)行解碼...
正確的編碼方式為:gbk
智能解碼結(jié)果: 你好世界

Process finished with exit code 0

2. 加密解密算法擴(kuò)展——重點(diǎn)?。?!

2.1 哈希算法(不可逆)

import hashlib
import hmac

def demo_hash_functions():
    """演示常用哈希函數(shù)"""
    data = "Hello World! 你好世界!"
    print(f"原始數(shù)據(jù): {data}")
    
    # MD5 (128位,已不推薦用于安全用途,但仍用于校驗(yàn))
    md5_hash = hashlib.md5(data.encode()).hexdigest()
    print(f"MD5: {md5_hash}")
    
    # SHA-256 (更安全)
    sha256_hash = hashlib.sha256(data.encode()).hexdigest()
    print(f"SHA-256: {sha256_hash}")
    
    # 加鹽哈希 (更安全)
    salt = "random_salt_123"
    salted_hash = hashlib.sha256((data + salt).encode()).hexdigest()
    print(f"加鹽SHA-256: {salted_hash}")
    
    # HMAC (密鑰相關(guān)的哈希)
    key = "secret_key"
    hmac_hash = hmac.new(key.encode(), data.encode(), hashlib.sha256).hexdigest()
    print(f"HMAC-SHA256: {hmac_hash}")

demo_hash_functions()

?? 注意閱讀上面的代碼示例,考慮以下幾個(gè)問題:

  1. 哈希算法到底是什么?哈希算法的用途有哪些?
  2. 為什么MD5哈希算法不推薦安全校驗(yàn)了?
  3. 其余的加鹽哈希、SHA-256、HMAC有什么用途,使用場(chǎng)景是什么?

哈希算法到底有什么作用?

哈希函數(shù)(常被不嚴(yán)謹(jǐn)?shù)胤Q為Hash加密,但其本質(zhì)是單向的,并非加密)的核心作用是為任意數(shù)據(jù)生成一個(gè)唯一的、固定長度的“數(shù)字指紋”。其主要用途包括:

  1. 數(shù)據(jù)完整性驗(yàn)證
    • 如上文所述,通過對(duì)比哈希值來確認(rèn)數(shù)據(jù)在傳輸或存儲(chǔ)過程中是否被改變。
  2. 安全存儲(chǔ)密碼
    • 系統(tǒng)不應(yīng)明文存儲(chǔ)用戶密碼。當(dāng)用戶注冊(cè)時(shí),系統(tǒng)對(duì)密碼進(jìn)行哈希并將哈希值存入數(shù)據(jù)庫。登錄時(shí),對(duì)用戶輸入的密碼再次進(jìn)行同樣的哈希操作,然后與數(shù)據(jù)庫中的哈希值對(duì)比。即使數(shù)據(jù)庫泄露,攻擊者看到的也只是哈希值,很難反推出原始密碼。
    • 這一點(diǎn)深有體會(huì),目前我們公司的產(chǎn)品服務(wù)對(duì)象多為國企和事業(yè)單位,近些年來不斷要求對(duì)數(shù)據(jù)進(jìn)行加密存儲(chǔ),許多新客戶也要求大部分的數(shù)據(jù)都要用密文存儲(chǔ),這導(dǎo)致間接的損失了一些客戶。
  3. 數(shù)字簽名與證書
    • 對(duì)消息或文件進(jìn)行哈希,然后對(duì)生成的哈希值進(jìn)行加密(即簽名),效率遠(yuǎn)高于加密整個(gè)文件。接收者可以驗(yàn)證哈希值來確認(rèn)文件的真實(shí)性和完整性。
  4. 數(shù)據(jù)唯一性標(biāo)識(shí)
    • 例如,Git使用SHA-1哈希來唯一標(biāo)識(shí)每一次提交和每一個(gè)文件。區(qū)塊鏈?zhǔn)褂霉礞溄用恳粋€(gè)區(qū)塊,確保其不可篡改性。
  5. 消息認(rèn)證碼(HMAC)
    • 如代碼中所示,HMAC結(jié)合一個(gè)密鑰和消息進(jìn)行哈希。用于驗(yàn)證消息不僅完整,而且確實(shí)來自擁有相同密鑰的發(fā)送方。

為什么MD5不安全了,但可以用于校驗(yàn)?

MD5為何不安全(針對(duì)密碼/防篡改):

  • 碰撞攻擊:MD5的核心漏洞是能夠被輕易地找到“碰撞”,即兩個(gè)不同的輸入產(chǎn)生相同的哈希值。攻擊者可以制造一個(gè)和原文件MD5值相同的惡意文件。
  • 計(jì)算速度過快:對(duì)于哈希函數(shù)來說,速度快在安全領(lǐng)域是缺點(diǎn)。這使得攻擊者可以用“BL破解”(嘗試所有可能組合)或“彩虹表”(預(yù)計(jì)算的哈希值數(shù)據(jù)庫)的方式快速反推原始數(shù)據(jù)。
  • 不再抗碰撞:在現(xiàn)代計(jì)算機(jī)上,可以在可接受的時(shí)間內(nèi)故意制造出MD5碰撞,這使得它無法用于驗(yàn)證數(shù)據(jù)的唯一性和真實(shí)性(即無法保證數(shù)據(jù)未被惡意替換)。

為何仍可用于校驗(yàn)(針對(duì)非惡意錯(cuò)誤)

  • 數(shù)據(jù)完整性校驗(yàn):在非安全敏感的場(chǎng)景下,如軟件下載、文件傳輸,MD5仍然可以用來檢查非惡意的數(shù)據(jù)損壞。例如,下載一個(gè)文件后計(jì)算MD5,與官網(wǎng)提供的MD5對(duì)比。如果不同,說明文件可能在網(wǎng)絡(luò)傳輸過程中出現(xiàn)了比特錯(cuò)誤。它的計(jì)算速度反而成了優(yōu)點(diǎn)。

  • 場(chǎng)景假設(shè)不同:在這種使用場(chǎng)景中,我們假設(shè)錯(cuò)誤是隨機(jī)發(fā)生的(如網(wǎng)絡(luò)丟包),而不是有一個(gè)主動(dòng)的攻擊者故意制造一個(gè)具有相同MD5值的惡意文件。對(duì)于隨機(jī)錯(cuò)誤,MD5的校驗(yàn)?zāi)芰σ廊皇亲銐虻摹?/p>

其他幾種加密方式的區(qū)別與使用場(chǎng)景

SHA-256

  • 是什么:SHA-2家族的一員,生成256位(32字節(jié))的哈希值。
  • 與MD5區(qū)別
    • 更安全:目前沒有公開的有效碰撞攻擊方法。
    • 更長的哈希值:256位 vs MD5的128位,大大增加了BL破解的難度。
    • 更慢:計(jì)算速度比MD5慢,這在安全上是優(yōu)點(diǎn)。
  • 使用場(chǎng)景
    • 替代MD5的所有安全場(chǎng)景:數(shù)字證書、SSL/TLS、區(qū)塊鏈(比特幣)、軟件完整性校驗(yàn)等。
    • 是目前廣泛推薦使用的通用安全哈希算法。

加鹽哈希(Salted Hash)

  • 是什么:在原始數(shù)據(jù)(如密碼)后面拼接一個(gè)隨機(jī)字符串(鹽)后再進(jìn)行哈希。
  • 與普通SHA-256區(qū)別
    • 防御彩虹表攻擊:即使兩個(gè)用戶的密碼相同,由于他們的“鹽”不同,最終的哈希值也完全不同。攻擊者無法使用一個(gè)預(yù)先計(jì)算好的彩虹表來批量破解密碼。
    • 強(qiáng)制個(gè)性化:即使攻擊者破解了其中一個(gè)密碼,也無法推知其他使用相同密碼的賬戶。
  • 使用場(chǎng)景
    • 密碼存儲(chǔ)的首選方法?,F(xiàn)代最佳實(shí)踐是使用專門的密碼哈希函數(shù)(如bcrypt, argon2),它們內(nèi)置了加鹽并且計(jì)算速度可調(diào)(故意慢),但“SHA-256 + 隨機(jī)鹽”的原理是相同的。

HMAC(密鑰散列消息認(rèn)證碼)

  • 是什么:一種使用加密哈希函數(shù)(如SHA-256)和一個(gè)密鑰來驗(yàn)證消息完整性和真實(shí)性的技術(shù)。
  • 與普通/加鹽哈希的根本區(qū)別
    • 需要密鑰:HMAC的計(jì)算過程依賴于一個(gè)雙方共享的密鑰。沒有密鑰,就無法計(jì)算出正確的HMAC值。
    • 目標(biāo)不同:普通哈希驗(yàn)證“數(shù)據(jù)是否被更改”,HMAC驗(yàn)證“數(shù)據(jù)是否被更改,且是否來自合法的、擁有密鑰的發(fā)送方”。
  • 使用場(chǎng)景
    • API請(qǐng)求認(rèn)證:客戶端和服務(wù)器共享一個(gè)密鑰,客戶端在發(fā)送請(qǐng)求時(shí)計(jì)算請(qǐng)求內(nèi)容的HMAC,服務(wù)器收到后使用相同密鑰驗(yàn)證HMAC,從而認(rèn)證客戶端身份并確保請(qǐng)求未被篡改。
    • JWT(JSON Web Tokens):可以使用HMAC進(jìn)行簽名。
    • 安全通信協(xié)議:在SSL/TLS等協(xié)議中也有應(yīng)用。

不同哈希加密方式總結(jié)和建議

方法核心特點(diǎn)安全性主要使用場(chǎng)景
MD5速度快,哈希值短不安全非惡意場(chǎng)景的數(shù)據(jù)完整性校驗(yàn)(如文件下載)
SHA-256安全性高,通用性強(qiáng)安全數(shù)字簽名、證書、區(qū)塊鏈、替代MD5的校驗(yàn)
加鹽哈希密碼+隨機(jī)鹽,防彩虹表安全密碼存儲(chǔ)(但更推薦bcrypt等)
HMAC消息+密鑰,驗(yàn)證來源和完整性安全API認(rèn)證、消息防篡改與身份驗(yàn)證

2.2 對(duì)稱加密(AES)

核心模式:“非對(duì)稱加密握手 + 對(duì)稱加密通話”。幾乎所有的現(xiàn)代安全通信協(xié)議都遵循這一高效且安全的模式。

宏觀角度分析對(duì)稱加密的使用場(chǎng)景

1. 數(shù)據(jù)存儲(chǔ)加密(全盤加密/文件加密)

?? 這是最直接的應(yīng)用場(chǎng)景,目的是保護(hù)靜態(tài)數(shù)據(jù)。

  • 全盤加密:像 Windows 的 BitLocker、macOS 的 FileVault、Linux 的 LUKS 都使用 AES 等對(duì)稱加密算法對(duì)整個(gè)硬盤驅(qū)動(dòng)器進(jìn)行加密。當(dāng)系統(tǒng)啟動(dòng)時(shí),通過密碼、TPM 芯片或 USB 密鑰來解鎖加密密鑰,之后的所有讀寫操作在后臺(tái)自動(dòng)加解密,用戶無感知。

  • 文件/文件夾加密:對(duì)單個(gè)文件或壓縮包進(jìn)行加密后存儲(chǔ)或傳輸。例如,使用 7-Zip 創(chuàng)建加密的壓縮包,或者使用 EFS(加密文件系統(tǒng))加密特定文件。

2. 安全網(wǎng)絡(luò)通信(TLS/SSL, VPN)

?? 雖然 TLS/SSL 使用非對(duì)稱加密來初始握手和身份驗(yàn)證,但一旦建立安全連接,所有后續(xù)數(shù)據(jù)的傳輸都使用對(duì)稱加密。

  • HTTPS 網(wǎng)站:當(dāng)你訪問一個(gè) HTTPS 網(wǎng)站時(shí),瀏覽器和服務(wù)器在握手階段協(xié)商出一個(gè)唯一的“會(huì)話密鑰”。之后,你們之間傳輸?shù)乃芯W(wǎng)頁內(nèi)容、Cookie、個(gè)人信息都使用這個(gè)對(duì)稱會(huì)話密鑰進(jìn)行加密,確保傳輸過程中不被竊聽和篡改。這也是為什么要單獨(dú)購買https流量的主要原因之一,會(huì)讓你的網(wǎng)頁更加安全。

  • 虛擬專用網(wǎng)絡(luò):VPN(如 IPsec, OpenVPN)同樣使用對(duì)稱加密來加密你的所有網(wǎng)絡(luò)流量,形成一個(gè)安全的“隧道”,保護(hù)你的上網(wǎng)行為不被本地網(wǎng)絡(luò)提供商或黑客窺探。

3. 數(shù)據(jù)庫加密

?? 為了保護(hù)數(shù)據(jù)庫中存儲(chǔ)的敏感信息(如用戶密碼哈希、個(gè)人信息、金融數(shù)據(jù)),可以使用對(duì)稱加密。

  • 列級(jí)加密:對(duì)數(shù)據(jù)庫中特定的敏感列(如“信用卡號(hào)”列)進(jìn)行加密。應(yīng)用程序在寫入數(shù)據(jù)前加密,在讀取數(shù)據(jù)后解密。這樣,即使數(shù)據(jù)庫文件被拖庫,攻擊者沒有密鑰也無法讀取明文信息。

4. 消息應(yīng)用與即時(shí)通訊

?? 像 WhatsApp、Signal、Telegram(秘密聊天)等應(yīng)用使用端到端加密。其原理是:

  • 使用非對(duì)稱加密協(xié)商或交換一個(gè)對(duì)稱密鑰。
  • 使用該對(duì)稱密鑰加密所有的聊天消息、圖片、文件。
  • 只有通信的雙方持有該密鑰,服務(wù)提供商本身也無法解密消息內(nèi)容。

5. 支付系統(tǒng)與金融交易

  • 銀行卡芯片:EMV 芯片卡在交易時(shí),與 POS 機(jī)進(jìn)行動(dòng)態(tài)認(rèn)證,過程中使用對(duì)稱加密來保護(hù)交易數(shù)據(jù)。

  • 支付網(wǎng)關(guān):處理信用卡交易時(shí),從商戶到支付網(wǎng)關(guān)的傳輸過程中,支付信息通常使用對(duì)稱加密保護(hù)。

6. 軟件與固件保護(hù)

  • 數(shù)字版權(quán)管理:為了保護(hù)版權(quán)內(nèi)容(如流媒體視頻、游戲、軟件),供應(yīng)商會(huì)使用對(duì)稱加密對(duì)內(nèi)容本身進(jìn)行加密,只有合法的、經(jīng)過授權(quán)的播放器或客戶端才能獲取密鑰進(jìn)行解密播放。
  • 固件更新:設(shè)備(如路由器、智能手機(jī))在進(jìn)行固件在線升級(jí)時(shí),下載的固件包通常是經(jīng)過對(duì)稱加密和簽名的,以防止攻擊者植入惡意固件。

Python代碼示例

注意?。?!

  • 下面的例子非常全面,每一步都有解釋,建議自己在Pycharm仔細(xì)閱讀。
"""
AES對(duì)稱加密解密工具類
改進(jìn)版:增加詳細(xì)注釋、錯(cuò)誤處理、類型提示和安全性增強(qiáng)
"""

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import base64
import os
from typing import Union, Optional


class AESCipher:
    """
    AES加密解密工具類
    使用CBC模式,PKCS7填充,支持AES-256加密
    """
    """
    __init__是Python對(duì)象創(chuàng)建后自動(dòng)執(zhí)行的初始化函數(shù)
    類似Java的構(gòu)造函數(shù),但是Java的構(gòu)造函數(shù)作用是創(chuàng)建對(duì)象
    而__init__是創(chuàng)建對(duì)象之后自動(dòng)執(zhí)行,Python中的構(gòu)造函數(shù)是__new__
    """
    """
    self是Python中實(shí)例化方法必須要有的一個(gè)參數(shù),作用類似于Java中的this
    但Java中this是隱式的,而Python中是顯式的,而且必須手動(dòng)申明
    """
    """
     key: Optional[bytes]類似于TypeScript寫法,用于限制參數(shù)的類型,一般寫法直接key=None即可
    """
    def __init__(self, key: Optional[bytes] = None):
        """
        初始化AES加密器

        作用:
        - 設(shè)置加密密鑰
        - 確定AES塊大小

        參數(shù):
        key: 可選的密鑰字節(jié),如果為None則自動(dòng)生成32字節(jié)(256位)隨機(jī)密鑰
        """
        # AES塊大小固定為16字節(jié)
        self.block_size = AES.block_size  # 值為16

        if key:
            # 驗(yàn)證密鑰長度
            if len(key) not in [16, 24, 32]:
                raise ValueError("密鑰長度必須為16(AES-128)、24(AES-192)或32(AES-256)字節(jié)")
            self.key = key
        else:
            # 生成32字節(jié)(256位)隨機(jī)密鑰 - AES-256
            # get_random_bytes()作用:生成密碼學(xué)安全的隨機(jī)字節(jié)序列
            self.key = get_random_bytes(32)

        print(f"[初始化] 密鑰長度: {len(self.key)}字節(jié), 塊大小: {self.block_size}字節(jié)")

    # -> str 這種寫法是用于定義函數(shù)的返回值類型為str字符串
    def encrypt(self, plaintext: str) -> str:
        """
        加密文本字符串

        步驟:
        1. 生成隨機(jī)初始化向量(IV)
        2. 創(chuàng)建AES加密器
        3. 對(duì)明文進(jìn)行填充
        4. 執(zhí)行加密
        5. 組合IV和密文
        6. Base64編碼返回

        參數(shù):
        plaintext: 要加密的原始文本

        返回:
        Base64編碼的加密字符串
        """
        print(f"\n[加密開始] 明文: '{plaintext}'")

        # 步驟1: 生成隨機(jī)初始化向量(IV)
        # IV作用:確保同樣的明文每次加密結(jié)果不同,增強(qiáng)安全性
        iv = get_random_bytes(self.block_size)
        print(f"[步驟1] 生成IV: {iv.hex()} (長度: {len(iv)}字節(jié))")

        # 步驟2: 創(chuàng)建AES加密器
        # AES.new()作用:創(chuàng)建AES加密對(duì)象
        # 參數(shù)說明:
        # - self.key: 加密密鑰
        # - AES.MODE_CBC: 密碼塊鏈模式
        # - iv: 初始化向量
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        print(f"[步驟2] 創(chuàng)建CBC模式加密器完成")

        # 步驟3: 將文本編碼為字節(jié)并填充
        # encode()作用:將字符串轉(zhuǎn)換為UTF-8編碼的字節(jié)序列
        plaintext_bytes = plaintext.encode('utf-8')
        print(f"[步驟3] 文本編碼為字節(jié): {plaintext_bytes} (長度: {len(plaintext_bytes)}字節(jié))")

        # pad()作用:使用PKCS7填充方案對(duì)數(shù)據(jù)進(jìn)行填充,使其長度為塊大小的整數(shù)倍
        # PKCS7填充原理:缺少n個(gè)字節(jié)就填充n個(gè)值為n的字節(jié)
        padded_bytes = pad(plaintext_bytes, self.block_size)
        print(f"[步驟3] PKCS7填充后: {padded_bytes} (長度: {len(padded_bytes)}字節(jié))")

        # 步驟4: 執(zhí)行加密
        # encrypt()作用:對(duì)填充后的數(shù)據(jù)進(jìn)行AES加密
        ciphertext = cipher.encrypt(padded_bytes)
        print(f"[步驟4] 加密完成,密文: {ciphertext.hex()} (長度: {len(ciphertext)}字節(jié))")

        # 步驟5: 組合IV和密文
        # IV + 密文的作用:解密時(shí)需要相同的IV,一起傳輸?shù)粫?huì)泄露密鑰
        encrypted_data = iv + ciphertext
        print(f"[步驟5] 組合IV和密文: {encrypted_data.hex()} (總長度: {len(encrypted_data)}字節(jié))")

        # 步驟6: Base64編碼
        # base64.b64encode()作用:將二進(jìn)制數(shù)據(jù)編碼為ASCII字符串,便于傳輸和存儲(chǔ)
        # decode()作用:將字節(jié)轉(zhuǎn)換為字符串
        result = base64.b64encode(encrypted_data).decode('utf-8')
        print(f"[步驟6] Base64編碼結(jié)果: {result}")

        print(f"[加密完成] 最終密文長度: {len(result)}字符")
        return result

    def decrypt(self, encrypted_text: str) -> str:
        """
        解密文本字符串

        步驟:
        1. Base64解碼
        2. 分離IV和密文
        3. 創(chuàng)建AES解密器
        4. 執(zhí)行解密
        5. 去除填充
        6. 解碼為字符串

        參數(shù):
        encrypted_text: Base64編碼的加密字符串

        返回:
        解密后的原始文本字符串
        """
        print(f"\n[解密開始] 密文: {encrypted_text[:50]}...")

        try:
            # 步驟1: Base64解碼
            # base64.b64decode()作用:將Base64字符串解碼回二進(jìn)制數(shù)據(jù)
            encrypted_data = base64.b64decode(encrypted_text)
            print(f"[步驟1] Base64解碼后數(shù)據(jù)長度: {len(encrypted_data)}字節(jié)")

            # 步驟2: 分離IV和密文
            # IV是前16字節(jié),剩余部分是密文
            iv = encrypted_data[:self.block_size]
            ciphertext = encrypted_data[self.block_size:]
            print(f"[步驟2] 分離IV: {iv.hex()} (長度: {len(iv)}字節(jié))")
            print(f"[步驟2] 分離密文: {ciphertext.hex()[:50]}... (長度: {len(ciphertext)}字節(jié))")

            # 步驟3: 創(chuàng)建AES解密器
            # 使用相同的密鑰和IV創(chuàng)建解密器
            cipher = AES.new(self.key, AES.MODE_CBC, iv)
            print(f"[步驟3] 創(chuàng)建CBC模式解密器完成")

            # 步驟4: 執(zhí)行解密
            # decrypt()作用:對(duì)密文進(jìn)行AES解密
            decrypted_padded = cipher.decrypt(ciphertext)
            print(f"[步驟4] 解密后數(shù)據(jù)(含填充): {decrypted_padded} (長度: {len(decrypted_padded)}字節(jié))")

            # 步驟5: 去除填充
            # unpad()作用:移除PKCS7填充,恢復(fù)原始數(shù)據(jù)
            decrypted_bytes = unpad(decrypted_padded, self.block_size)
            print(f"[步驟5] 去除填充后: {decrypted_bytes} (長度: {len(decrypted_bytes)}字節(jié))")

            # 步驟6: 解碼為字符串
            # decode()作用:將UTF-8字節(jié)序列轉(zhuǎn)換回字符串
            result = decrypted_bytes.decode('utf-8')
            print(f"[步驟6] 解碼為字符串: '{result}'")

            print(f"[解密完成] 成功恢復(fù)明文")
            return result

        except Exception as e:
            error_msg = f"解密失敗: {e}"
            print(f"[錯(cuò)誤] {error_msg}")
            raise ValueError(error_msg)

    def get_key_base64(self) -> str:
        """
        獲取Base64編碼的密鑰(用于安全存儲(chǔ))

        作用:
        - 將二進(jìn)制密鑰轉(zhuǎn)換為可安全存儲(chǔ)的字符串格式
        """
        return base64.b64encode(self.key).decode('utf-8')

    def set_key_from_base64(self, key_b64: str) -> None:
        """
        從Base64字符串設(shè)置密鑰

        作用:
        - 從存儲(chǔ)的Base64字符串恢復(fù)密鑰
        """
        self.key = base64.b64decode(key_b64)


def demo_aes_encryption():
    """
    演示AES加密解密的完整流程
    """
    print("\n" + "=" * 60)
    print("AES對(duì)稱加密完整演示")
    print("=" * 60)

    # 創(chuàng)建加密器實(shí)例
    print("1. 創(chuàng)建AES加密器...")
    cipher = AESCipher()

    # 測(cè)試數(shù)據(jù)
    test_cases = [
        "這是一段需要加密的敏感信息!",
        "Hello, World!",
        "短文本",
        "Very long text " * 10  # 測(cè)試長文本
    ]

    # enumerate是內(nèi)置函數(shù),用于在循環(huán)時(shí)同時(shí)獲取索引和元素值,第二個(gè)參數(shù)是定義開始索引的,表示i的起始值
    # 但這不代表我們可以用test_cases[i]取數(shù),這只是內(nèi)置函數(shù)給我們自動(dòng)將i進(jìn)行計(jì)算而已
    for i, original_text in enumerate(test_cases, 1):
        print(f"\n{'#' * 40}")
        print(f"測(cè)試案例 {i}: '{original_text[:30]}{'...' if len(original_text) > 30 else ''}'")
        print(f"{'#' * 40}")

        try:
            # 加密演示
            print(f"原始文本長度: {len(original_text)}字符")

            encrypted = cipher.encrypt(original_text)
            print(f"? 加密成功")

            # 解密演示
            decrypted = cipher.decrypt(encrypted)
            print(f"? 解密成功")

            # 驗(yàn)證結(jié)果
            if original_text == decrypted:
                print(f"? 驗(yàn)證通過: 原始文本與解密文本一致")
            else:
                print(f"? 驗(yàn)證失敗: 文本不一致")

        except Exception as e:
            print(f"? 加解密過程出錯(cuò): {e}")

    # 密鑰管理演示
    print(f"\n{'#' * 40}")
    print("密鑰管理演示")
    print(f"{'#' * 40}")

    # 保存密鑰
    saved_key = cipher.get_key_base64()
    print(f"Base64編碼密鑰: {saved_key}")

    # 使用保存的密鑰創(chuàng)建新加密器
    print("\n使用保存的密鑰創(chuàng)建新加密器...")
    new_cipher = AESCipher()
    new_cipher.set_key_from_base64(saved_key)

    # 測(cè)試密鑰兼容性
    test_text = "測(cè)試密鑰兼容性"
    encrypted = cipher.encrypt(test_text)
    decrypted = new_cipher.decrypt(encrypted)

    if test_text == decrypted:
        print("? 密鑰兼容性測(cè)試通過")
    else:
        print("? 密鑰兼容性測(cè)試失敗")


def security_considerations():
    """
    安全性考慮和建議
    """
    print(f"\n{'#' * 40}")
    print("安全性考慮和建議")
    print(f"{'#' * 40}")

    considerations = [
        "? 使用CBC模式,每次加密生成隨機(jī)IV,避免相同明文產(chǎn)生相同密文",
        "? 使用PKCS7填充,符合密碼學(xué)標(biāo)準(zhǔn)",
        "? 默認(rèn)使用AES-256(32字節(jié)密鑰),提供強(qiáng)安全性",
        "??  密鑰必須安全存儲(chǔ),不要硬編碼在代碼中",
        "??  考慮使用環(huán)境變量或密鑰管理服務(wù)存儲(chǔ)密鑰",
        "??  CBC模式需要正確的IV管理,確保每次加密使用不同IV",
        "?? 對(duì)于大量數(shù)據(jù),考慮使用GCM模式提供認(rèn)證加密",
        "?? 在生產(chǎn)環(huán)境中添加完整性校驗(yàn)(MAC)"
    ]

    for consideration in considerations:
        print(consideration)


if __name__ == "__main__":
    # 執(zhí)行演示
    demo_aes_encryption()
    security_considerations()

總結(jié)一下上面的例子,非常的nice我只能說,至少用于對(duì)稱加密的學(xué)習(xí)那是相當(dāng)?shù)膲蛴谩?/strong>

  1. 首先利用get_random_bytes隨機(jī)生成32位的密鑰。
  2. 之后使用get_random_bytes生成隨機(jī)的iv,iv的作用是為了相同的內(nèi)容密文也是不同的。
  3. 利用上面的iv和密鑰創(chuàng)建AES加密容器。
  4. 將明文用UTF-8進(jìn)行encode,然后使用pad進(jìn)行填充,要保證是塊大小的整數(shù)倍。
  5. 執(zhí)行加密,之后組合iv和密文并進(jìn)行Base64編碼,方便存儲(chǔ)和傳輸。

那么上面的加密過程已經(jīng)清晰了,解密則相反,只不過有一個(gè)致命的問題,在生產(chǎn)環(huán)境中,密鑰怎么進(jìn)行存儲(chǔ)?總不能傳輸給后臺(tái)吧,那不是泄露了嗎,畢竟這種規(guī)則都是通用的,可以被破解,而密鑰的管理要用到非對(duì)稱加密,我們接下來再說。

2.3 非對(duì)稱加密(RSA)

RSA的實(shí)現(xiàn)流程

  • 密鑰生成:創(chuàng)建私鑰/公鑰對(duì)
  • 公鑰加密:使用公鑰加密數(shù)據(jù)
  • 私鑰解密:使用私鑰解密數(shù)據(jù)

RSA的程序特性

  • 非對(duì)稱性:加密和解密使用不同的密鑰。
  • 安全性高:底層使用復(fù)雜的數(shù)學(xué)算法,有效的保證了安全。
  • 速度較慢:對(duì)比AES對(duì)稱加密慢100-1000倍。
  • 長度限制:一次性加密的數(shù)據(jù)量有限制。
  • 密鑰對(duì)管理:公鑰可公開,私鑰必須保密。

RSA使用場(chǎng)景

  • 安全通信初始化(TLS/SSL握手)
  • 數(shù)字簽名和身份驗(yàn)證
  • 安全電子郵件(PGP)
  • SSH遠(yuǎn)程登錄
  • 區(qū)塊鏈和加密貨幣
  • API安全認(rèn)證
  • 數(shù)字證書(PKI)

RSA代碼示例

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64

class RSACipher:
    """RSA非對(duì)稱加密解密工具類"""
    
    def __init__(self, key_size=2048):
        """
        初始化RSA密鑰對(duì)
        
        步驟作用:
        1. 設(shè)置密鑰長度(2048位是當(dāng)前安全標(biāo)準(zhǔn))
        2. 生成RSA密鑰對(duì)
        3. 分離公鑰和私鑰
        """
        self.key_size = key_size  # 密鑰位數(shù),決定安全性
        # RSA.generate()作用:生成RSA密鑰對(duì),基于大素?cái)?shù)分解難題
        self.key_pair = RSA.generate(key_size)
        # 私鑰:用于解密和簽名,必須保密
        self.private_key = self.key_pair
        # 公鑰:用于加密和驗(yàn)證,可以公開分發(fā)
        self.public_key = self.key_pair.publickey()
        print(f"[RSA初始化] 生成{key_size}位密鑰對(duì)完成")
    
    def encrypt(self, plaintext, public_key=None):
        """使用公鑰加密
        
        步驟作用:
        1. 創(chuàng)建PKCS1_OAEP加密器
        2. 將文本轉(zhuǎn)換為字節(jié)
        3. 檢查長度限制(RSA不能加密太長數(shù)據(jù))
        4. 執(zhí)行加密
        5. Base64編碼便于傳輸
        """
        try:
            # PKCS1_OAEP.new()作用:創(chuàng)建使用OAEP填充的RSA加密器
            # OAEP填充:增加隨機(jī)性,防止確定性攻擊
            cipher = PKCS1_OAEP.new(public_key or self.public_key)
            
            # encode()作用:將字符串轉(zhuǎn)換為UTF-8字節(jié)序列
            plaintext_bytes = plaintext.encode('utf-8')
            
            # RSA長度限制計(jì)算:
            # - 密鑰大?。簁ey_size//8 = 字節(jié)數(shù)
            # - OAEP填充占用42字節(jié)
            max_length = (self.key_size // 8) - 42
            print(f"[RSA加密] 明文長度: {len(plaintext_bytes)}字節(jié), 最大支持: {max_length}字節(jié)")
            
            if len(plaintext_bytes) > max_length:
                raise ValueError(f"文本過長,最大支持 {max_length} 字節(jié)")
            
            # encrypt()作用:使用公鑰加密數(shù)據(jù)
            # 原理:使用公鑰的指數(shù)e和模數(shù)n進(jìn)行模冪運(yùn)算
            ciphertext = cipher.encrypt(plaintext_bytes)
            print(f"[RSA加密] 加密完成,密文長度: {len(ciphertext)}字節(jié)")
            
            # base64編碼:將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為可安全傳輸?shù)奈谋靖袷?
            return base64.b64encode(ciphertext).decode('utf-8')
        except Exception as e:
            return f"加密失敗: {e}"
    
    def decrypt(self, ciphertext):
        """使用私鑰解密
        
        步驟作用:
        1. Base64解碼
        2. 創(chuàng)建PKCS1_OAEP解密器
        3. 使用私鑰解密
        4. 將字節(jié)轉(zhuǎn)換回字符串
        """
        try:
            # 創(chuàng)建使用私鑰的解密器
            cipher = PKCS1_OAEP.new(self.private_key)
            
            # base64解碼:將文本格式轉(zhuǎn)換回二進(jìn)制數(shù)據(jù)
            ciphertext_bytes = base64.b64decode(ciphertext)
            print(f"[RSA解密] 密文長度: {len(ciphertext_bytes)}字節(jié)")
            
            # decrypt()作用:使用私鑰解密數(shù)據(jù)
            # 原理:使用私鑰的指數(shù)d和模數(shù)n進(jìn)行模冪運(yùn)算
            decrypted_bytes = cipher.decrypt(ciphertext_bytes)
            print(f"[RSA解密] 解密完成,明文長度: {len(decrypted_bytes)}字節(jié)")
            
            # decode()作用:將UTF-8字節(jié)序列轉(zhuǎn)換回字符串
            return decrypted_bytes.decode('utf-8')
        except Exception as e:
            return f"解密失敗: {e}"
    
    def get_public_key_pem(self):
        """獲取PEM格式的公鑰
        作用:將公鑰轉(zhuǎn)換為標(biāo)準(zhǔn)PEM格式,便于存儲(chǔ)和傳輸"""
        return self.public_key.export_key().decode('utf-8')
    
    def get_private_key_pem(self):
        """獲取PEM格式的私鑰
        作用:將私鑰轉(zhuǎn)換為標(biāo)準(zhǔn)PEM格式,便于安全存儲(chǔ)"""
        return self.private_key.export_key().decode('utf-8')

RSA和AES的組合使用

"""
混合加密系統(tǒng):RSA加密AES密鑰 + AES加密實(shí)際數(shù)據(jù)
這是行業(yè)標(biāo)準(zhǔn)做法,兼顧安全性和性能
"""

class HybridEncryptionSystem:
    def __init__(self):
        # RSA用于密鑰交換
        self.rsa_cipher = RSACipher()
        # AES用于數(shù)據(jù)加密
        self.aes_cipher = AESCipher()
    
    def encrypt_data(self, plaintext: str, recipient_public_key) -> dict:
        """
        加密流程:
        1. 使用AES加密原始數(shù)據(jù)(高效)
        2. 使用RSA加密AES密鑰(安全傳輸)
        """
        # AES加密數(shù)據(jù)
        encrypted_data = self.aes_cipher.encrypt(plaintext)
        
        # RSA加密AES密鑰
        encrypted_key = self.rsa_cipher.encrypt(
            self.aes_cipher.get_key_base64(), 
            recipient_public_key
        )
        
        return {
            "encrypted_data": encrypted_data,
            "encrypted_aes_key": encrypted_key,
            "rsa_public_key": self.rsa_cipher.get_public_key_pem()  # 可選,用于回復(fù)
        }
    
    def decrypt_data(self, encrypted_package: dict, rsa_private_key) -> str:
        """
        解密流程:
        1. 使用RSA私鑰解密AES密鑰
        2. 使用AES密鑰解密數(shù)據(jù)
        """
        # 解密AES密鑰
        decrypted_key_b64 = self.rsa_cipher.decrypt(
            encrypted_package["encrypted_aes_key"], 
            rsa_private_key
        )
        
        # 設(shè)置AES密鑰
        self.aes_cipher.set_key_from_base64(decrypted_key_b64)
        
        # 解密數(shù)據(jù)
        return self.aes_cipher.decrypt(encrypted_package["encrypted_data"])

# 使用示例
def hybrid_encryption_demo():
    # 發(fā)送方
    sender = HybridEncryptionSystem()
    
    # 接收方的RSA公鑰(假設(shè)已安全獲取)
    recipient_public_key = "接收方的RSA公鑰PEM格式"
    
    # 加密數(shù)據(jù)
    original_data = "敏感業(yè)務(wù)數(shù)據(jù)"
    encrypted_package = sender.encrypt_data(original_data, recipient_public_key)
    
    print("加密完成:")
    print(f"- AES加密數(shù)據(jù)長度: {len(encrypted_package['encrypted_data'])}")
    print(f"- RSA加密的AES密鑰: {encrypted_package['encrypted_aes_key'][:50]}...")
    
    # 接收方解密(使用自己的RSA私鑰)
    # decrypted = recipient.decrypt_data(encrypted_package, recipient_private_key)

上述代碼的核心就是使用RSA來加密AES的密鑰,傳輸數(shù)據(jù)的時(shí)候?qū)ES加密后的密鑰和加密的數(shù)據(jù)一起傳輸,之后服務(wù)端用私鑰進(jìn)行解密

RSA私鑰的安全存儲(chǔ)方案

1. 硬件安全模塊(HSM)

?? 最安全的方案,私鑰永遠(yuǎn)不出硬件

  • 原理: 專用硬件設(shè)備,私鑰在硬件內(nèi)生成和存儲(chǔ),永不導(dǎo)出
  • 優(yōu)點(diǎn): 最高安全性,防物理攻擊
  • 缺點(diǎn): 成本高,部署復(fù)雜
  • 適用: 金融、政府、大型企業(yè)

2. 云密鑰管理服務(wù)(KMS)

  • 原理: 使用云服務(wù)商的密鑰管理服務(wù),應(yīng)用程序通過API調(diào)用加解密
  • 優(yōu)點(diǎn): 易用,無需管理密鑰基礎(chǔ)設(shè)施
  • 缺點(diǎn): 依賴云服務(wù)商,可能有合規(guī)問題
  • 適用: 云原生應(yīng)用,中小企業(yè)

3. 密碼加密存儲(chǔ)

from Crypto.Protocol.KDF import PBKDF2
        from Crypto.Cipher import AES
        import os
        
        # 生成加密密鑰
        salt = os.urandom(32)
        key = PBKDF2(password, salt, 32, count=100000)
        
        # 加密私鑰
        private_key_pem = "RSA私鑰PEM內(nèi)容"
        iv = os.urandom(16)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        encrypted_private_key = cipher.encrypt(pad(private_key_pem.encode(), 16))
        
        # 存儲(chǔ):salt + iv + 加密私鑰
        storage_data = salt + iv + encrypted_private_key
        
        return {
            "存儲(chǔ)格式": "salt(32) + iv(16) + 加密私鑰",
            "解密要求": "需要正確密碼",
            "安全性": "中等,依賴密碼強(qiáng)度"
        }

4. 環(huán)境變量 + 文件權(quán)限

  1. 將私鑰文件放在安全目錄
  2. 設(shè)置嚴(yán)格文件權(quán)限(chmod 600)
  3. 通過環(huán)境變量指定密鑰路徑
  4. 應(yīng)用程序運(yùn)行時(shí)讀取

5. 如何選擇合適的加密方案

根據(jù)需求和企業(yè)的實(shí)力進(jìn)行選擇,一般來說大部分使用的都是環(huán)境變量+文件的方案,稍微大點(diǎn)的企業(yè)使用第三方進(jìn)行密鑰管理也完全足夠了,只有像政府和大型企業(yè)才會(huì)采用最復(fù)雜的HSM進(jìn)行加密。

三、數(shù)據(jù)驗(yàn)證的方法

?? 這里說的數(shù)據(jù)驗(yàn)證是通過程序自帶的字符串方法檢查數(shù)據(jù)是否簡單的符合自己的要求,也就是下面這些方法的使用,上面已經(jīng)說過了。

# .startswith(prefix): 檢查是否以指定前綴開頭
filename = "document.pdf"
print(filename.startswith("doc"))    # 輸出: True
print(filename.startswith("xls"))    # 輸出: False

# .endswith(suffix): 檢查是否以指定后綴結(jié)尾  
print(filename.endswith(".pdf"))     # 輸出: True
print(filename.endswith(".docx"))    # 輸出: False

# .isalpha(): 是否全是字母(中文也被認(rèn)為是字母)
print("Hello".isalpha())      # 輸出: True
print("Hello123".isalpha())   # 輸出: False
print("你好".isalpha())        # 輸出: True

# .isdigit(): 是否全是數(shù)字
print("123".isdigit())        # 輸出: True
print("12.3".isdigit())       # 輸出: False

# .isalnum(): 是否全是字母或數(shù)字
print("Hello123".isalnum())   # 輸出: True
print("Hello 123".isalnum())  # 輸出: False(包含空格)

# .isspace(): 是否全是空白字符
print("   ".isspace())        # 輸出: True
print("  x  ".isspace())      # 輸出: False

1. 主流數(shù)據(jù)驗(yàn)證庫介紹

1. Pydantic(最推薦)

"""
Pydantic - 現(xiàn)代Python的數(shù)據(jù)驗(yàn)證和設(shè)置管理
特點(diǎn):性能高、類型提示友好、功能強(qiáng)大
安裝:pip install pydantic
"""

from pydantic import BaseModel, EmailStr, validator, Field
from typing import Optional
import re

class User(BaseModel):
    # 基礎(chǔ)字段驗(yàn)證
    name: str = Field(..., min_length=1, max_length=50)
    age: int = Field(..., ge=0, le=150)  # 大于等于0,小于等于150
    
    # 內(nèi)置郵箱驗(yàn)證
    email: EmailStr
    
    # 自定義手機(jī)號(hào)驗(yàn)證
    phone: str = Field(..., regex=r'^1[3-9]\d{9}$')
    
    # 自定義驗(yàn)證器
    @validator('name')
    def name_must_contain_letters(cls, v):
        if not any(c.isalpha() for c in v):
            raise ValueError('姓名必須包含字母')
        return v.title()  # 自動(dòng)格式化
    
    @validator('phone')
    def validate_phone_format(cls, v):
        if not re.match(r'^1[3-9]\d{9}$', v):
            raise ValueError('手機(jī)號(hào)格式不正確')
        return v

# 使用示例
def pydantic_demo():
    # 正確數(shù)據(jù)
    try:
        user = User(
            name="張三",
            age=25,
            email="test@example.com", 
            phone="13800138000"
        )
        print(f"驗(yàn)證成功: {user.dict()}")
    except Exception as e:
        print(f"驗(yàn)證失敗: {e}")
    
    # 錯(cuò)誤數(shù)據(jù)測(cè)試
    test_cases = [
        {"name": "", "age": 25, "email": "invalid", "phone": "123"},
        {"name": "John", "age": 200, "email": "test@example.com", "phone": "13800138000"},
    ]
    
    for data in test_cases:
        try:
            user = User(**data)
        except Exception as e:
            print(f"驗(yàn)證失敗: {e}")

pydantic_demo()

2. Cerberus(輕量靈活)

"""
Cerberus - 輕量級(jí)數(shù)據(jù)驗(yàn)證庫
特點(diǎn):Schema定義簡單、靈活性強(qiáng)
安裝:pip install cerberus
"""

from cerberus import Validator

# 定義驗(yàn)證規(guī)則
user_schema = {
    'name': {
        'type': 'string', 
        'minlength': 1, 
        'maxlength': 50,
        'required': True
    },
    'age': {
        'type': 'integer', 
        'min': 0, 
        'max': 150,
        'required': True
    },
    'email': {
        'type': 'string', 
        'regex': r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
        'required': True
    },
    'phone': {
        'type': 'string', 
        'regex': r'^1[3-9]\d{9}$',
        'required': True
    }
}

# 自定義驗(yàn)證規(guī)則
def validate_email_domain(field, value, error):
    """自定義郵箱域名驗(yàn)證"""
    blocked_domains = ['temp-mail.org', '10minutemail.com']
    domain = value.split('@')[1]
    if domain in blocked_domains:
        error(field, f"不允許使用臨時(shí)郵箱域名: {domain}")

user_schema['email']['validator'] = validate_email_domain

def cerberus_demo():
    validator = Validator(user_schema)
    
    # 測(cè)試數(shù)據(jù)
    test_data = {
        'name': '李四',
        'age': 30,
        'email': 'lisi@example.com',
        'phone': '13900139000'
    }
    
    if validator.validate(test_data):
        print("數(shù)據(jù)驗(yàn)證通過")
        print(f"規(guī)范化后的數(shù)據(jù): {validator.document}")
    else:
        print("數(shù)據(jù)驗(yàn)證失敗:")
        print(f"錯(cuò)誤信息: {validator.errors}")

cerberus_demo()

3. Voluptuous(語法優(yōu)雅)

"""
Voluptuous - 專注于數(shù)據(jù)驗(yàn)證的庫
特點(diǎn):語法優(yōu)雅、錯(cuò)誤信息清晰
安裝:pip install voluptuous
"""

from voluptuous import Schema, Required, All, Length, Range, Email, Url, MultipleInvalid
import re

# 定義驗(yàn)證schema
user_schema = Schema({
    Required('name'): All(str, Length(min=1, max=50)),
    Required('age'): All(int, Range(min=0, max=150)),
    Required('email'): Email(),
    Required('phone'): All(str, Length(min=11, max=11)),
    'website': Url(),  # 可選字段
})

# 自定義驗(yàn)證函數(shù)
def validate_phone(value):
    if not re.match(r'^1[3-9]\d{9}$', value):
        raise ValueError('手機(jī)號(hào)格式不正確')
    return value

# 更新schema加入自定義驗(yàn)證
user_schema = Schema({
    Required('name'): All(str, Length(min=1, max=50)),
    Required('age'): All(int, Range(min=0, max=150)),
    Required('email'): Email(),
    Required('phone'): All(str, Length(min=11, max=11), validate_phone),
})

def voluptuous_demo():
    # 正確數(shù)據(jù)
    valid_data = {
        'name': '王五',
        'age': 28,
        'email': 'wangwu@example.com',
        'phone': '13700137000'
    }
    
    try:
        result = user_schema(valid_data)
        print(f"驗(yàn)證成功: {result}")
    except MultipleInvalid as e:
        print(f"驗(yàn)證失敗: {e}")
    
    # 錯(cuò)誤數(shù)據(jù)
    invalid_data = {
        'name': '',
        'age': 200,
        'email': 'invalid-email',
        'phone': '123'
    }
    
    try:
        result = user_schema(invalid_data)
    except MultipleInvalid as e:
        print(f"驗(yàn)證失敗詳情:")
        for error in e.errors:
            print(f"- {error}")

voluptuous_demo()

四、正則表達(dá)式的使用

1. re模塊

1.1 基本使用

import re

# re模塊核心函數(shù)
text = "我的電話是138-0013-8000,郵箱是test@example.com"

# 1. re.search() - 查找第一個(gè)匹配
match = re.search(r'\d{3}-\d{4}-\d{4}', text)
if match:
    print(f"找到電話: {match.group()}")  # 138-0013-8000

# 2. re.findall() - 查找所有匹配
emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', text)
print(f"所有郵箱: {emails}")  # ['test@example.com']

# 3. re.finditer() - 返回迭代器(可獲取位置)
for match in re.finditer(r'\d+', text):
    print(f"數(shù)字: {match.group()}, 位置: {match.span()}")

# 4. re.sub() - 替換
anonymized = re.sub(r'\d{4}$', 'XXXX', '13800138000')
print(f"匿名化: {anonymized}")  # 1380013XXXX

# 5. re.split() - 分割
parts = re.split(r'[,。]', "你好,世界。今天天氣不錯(cuò)。")
print(f"分割結(jié)果: {parts}")  # ['你好', '世界', '今天天氣不錯(cuò)', '']
函數(shù)名基本使用示例功能描述
re.search()match = re.search(r'\d{3}-\d{4}-\d{4}', text)
if match: print(match.group())
在字符串中搜索第一個(gè)匹配正則表達(dá)式的模式,返回匹配對(duì)象或None
re.findall()emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', text)查找字符串中所有匹配正則表達(dá)式的子串,以列表形式返回所有匹配結(jié)果
re.finditer()for match in re.finditer(r'\d+', text):
print(f"數(shù)字: {match.group()}, 位置: {match.span()}")
查找所有匹配項(xiàng),返回一個(gè)迭代器,每個(gè)元素都是匹配對(duì)象,可獲取匹配內(nèi)容和位置信息
re.sub()anonymized = re.sub(r'\d{4}$', 'XXXX', '13800138000')使用指定的替換字符串替換所有匹配正則表達(dá)式的子串
re.split()parts = re.split(r'[,。]', "你好,世界。今天天氣不錯(cuò)。")根據(jù)正則表達(dá)式模式分割字符串,返回分割后的子串列表

1.2 正則表達(dá)式語法詳解

"""
正則表達(dá)式元字符和語法
"""

def regex_syntax_demo():
    text = "價(jià)格是¥100.50,折扣后¥80.25,聯(lián)系人: 張先生"
    
    # 字符類
    print("1. 字符類:")
    print(re.findall(r'[張李王]先生', text))  # ['張先生']
    print(re.findall(r'[0-9]', text))  # ['1', '0', '0', '5', '0', '8', '0', '2', '5']
    
    # 量詞
    print("\n2. 量詞:")
    print(re.findall(r'\d+', text))  # ['100', '50', '80', '25'] - 1次或多次
    print(re.findall(r'\d*', text))  # 包含空字符串
    print(re.findall(r'\d{2,3}', text))  # ['100', '50', '80', '25'] - 2到3次
    print(re.findall(r'¥\d+\.?\d*', text))  # ['¥100.50', '¥80.25']
    
    # 邊界和位置
    print("\n3. 邊界匹配:")
    print(re.findall(r'^價(jià)格', text))  # ['價(jià)格'] - 開頭
    print(re.findall(r'先生$', "張先生"))  # ['先生'] - 結(jié)尾
    print(re.findall(r'\b聯(lián)系人', text))  # ['聯(lián)系人'] - 單詞邊界
    
    # 分組和捕獲
    print("\n4. 分組捕獲:")
    match = re.search(r'¥(\d+)\.(\d+)', text)
    if match:
        print(f"完整匹配: {match.group(0)}")  # ¥100.50
        print(f"整數(shù)部分: {match.group(1)}")  # 100
        print(f"小數(shù)部分: {match.group(2)}")  # 50
        print(f"所有分組: {match.groups()}")  # ('100', '50')

regex_syntax_demo()

1.3. 高級(jí)特性

import re
def advanced_regex_features():
    """高級(jí)正則特性"""

    text = """
    用戶信息:
    - 姓名: 張三, 年齡: 25, 郵箱: zhangsan@example.com
    - 姓名: 李四, 年齡: 30, 郵箱: lisi@test.org
    - 姓名: 王五, 年齡: 28, 郵箱: wangwu@domain.cn
    """

    # 1. 命名分組
    pattern = r"姓名: (?P<name>[^,]+), 年齡: (?P<age>\d+), 郵箱: (?P<email>[^\s]+)"

    for match in re.finditer(pattern, text):
        print(f"\n命名分組結(jié)果:")
        print(f"  姓名: {match.group('name')}")
        print(f"  年齡: {match.group('age')}")
        print(f"  郵箱: {match.group('email')}")

    # 2. 非捕獲分組
    # (?:...) 不捕獲的分組
    numbers = "100元 200美元 300歐元"
    currencies = re.findall(r'(\d+)(?:元|美元|歐元)', numbers)
    print(f"\n非捕獲分組: {currencies}")  # ['100', '200', '300']

    # 3. 前后查找
    # (?=...) 正向肯定前瞻, (?!...) 正向否定前瞻
    # (?<=...) 正向肯定后顧, (?<!...) 正向否定后顧

    # 匹配后面是"元"的數(shù)字
    prices = re.findall(r'\d+(?=元)', numbers)
    print(f"價(jià)格(元): {prices}")  # ['100']

    # 匹配前面是"$"的數(shù)字
    dollar_text = "價(jià)格$100 重量100kg"
    dollar_prices = re.findall(r'(?<=\$)\d+', dollar_text)
    print(f"美元價(jià)格: {dollar_prices}")  # ['100']

    # 4. 條件匹配
    pattern = r'(\d+)(?(1)元|美元)'  # 如果有分組1匹配"元",否則匹配"美元"

    # 5. 注釋和詳細(xì)模式
    complex_pattern = r"""
        ^                   # 字符串開始
        (\w+)               # 用戶名 - 分組1
        @                   # @符號(hào)
        (\w+                # 域名前綴 - 分組2
        \.                  # 點(diǎn)號(hào)
        \w+)                # 域名后綴 - 分組3
        $                   # 字符串結(jié)束
    """

    email = "user@example.com"
    match = re.search(complex_pattern, email, re.VERBOSE)
    if match:
        print(f"\n詳細(xì)模式解析:")
        print(f"  用戶名: {match.group(1)}")
        print(f"  域名: {match.group(2)}")

advanced_regex_features()

2. regex庫

regex庫要比re庫更加全面,支持的場(chǎng)景更多,目前可以作為了解,如果有復(fù)雜的需求可以考慮使用regex庫進(jìn)行解決,一般的需求re庫就可以支持,regex更多用于復(fù)雜的需求比如日志分析。

"""
regex庫 - 更強(qiáng)大、更兼容的正則表達(dá)式庫
安裝: pip install regex
特點(diǎn): 支持更多特性、更好的Unicode支持、兼容re API
"""

import regex  # 注意導(dǎo)入的是regex不是re

def regex_library_demo():
    """regex庫高級(jí)特性演示"""
    
    text = "測(cè)試unicode: ???? 表情符號(hào)和中文"
    
    # 1. 更好的Unicode支持
    print("1. Unicode支持:")
    # 匹配所有字母字符(包括中文)
    print(regex.findall(r'\p{L}+', text))  # ['測(cè)試unicode', '表情符號(hào)和中文']
    # 匹配表情符號(hào)
    print(regex.findall(r'\p{Emoji}', text))  # ['??', '??']
    
    # 2. 重疊匹配
    print("\n2. 重疊匹配:")
    text = "aaa"
    # 標(biāo)準(zhǔn)re庫只能找到 ['aaa']
    # regex可以找到所有重疊匹配
    matches = regex.findall(r'a.a', text, overlapped=True)
    print(f"重疊匹配: {matches}")  # ['aaa']
    
    # 3. 模糊匹配(容錯(cuò)匹配)
    print("\n3. 模糊匹配:")
    text = "color centre favorite"
    # 允許拼寫錯(cuò)誤(美式vs英式英語)
    pattern = regex.compile(r'(?e)(color){e<=1}')  # 允許1個(gè)錯(cuò)誤
    matches = pattern.findall(text)
    print(f"模糊匹配: {matches}")  # ['color', 'colou']
    
    # 4. 遞歸模式
    print("\n4. 遞歸模式:")
    html = "<div>內(nèi)容<span>嵌套</span>更多內(nèi)容</div>"
    # 匹配嵌套的HTML標(biāo)簽
    pattern = regex.compile(r'<([^>]+)>(?:[^<>]|(?R))*</\1>')
    matches = pattern.findall(html)
    print(f"遞歸匹配: {matches}")
    
    # 5. 集合操作
    print("\n5. 集合操作:")
    text = "abc123漢字??"
    # 匹配數(shù)字或字母
    matches = regex.findall(r'[[:alnum:]]', text)
    print(f"字母數(shù)字: {matches}")
    
    # 6. 分支重置
    print("\n6. 分支重置:")
    text = "日期: 2023-01-15 或 2023/01/15"
    # 使用分支重置組,組號(hào)在不同分支中保持一致
    pattern = r'(\d{4})(?|-(0[1-9]|1[0-2])-([0-2][0-9]|3[01])|/(0[1-9]|1[0-2])/([0-2][0-9]|3[01]))'
    matches = regex.findall(pattern, text)
    print(f"分支重置匹配: {matches}")

regex_library_demo()

總結(jié)

這篇文章的重點(diǎn)還是在加密那里,是非常重要的知識(shí)點(diǎn),我們閱讀文章的時(shí)候不需要將所有的知識(shí)點(diǎn)都牢記,代碼還是更多的在編寫上,寫的多了熟悉就好了,我們可以有一個(gè)簡單的記憶,等到后面用的時(shí)候也知道一個(gè)方向,然后利用AI快速的解決問題。

到此這篇關(guān)于Python字符串相關(guān)操作及正則表達(dá)式的文章就介紹到這了,更多相關(guān)Python字符串及正則表達(dá)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python實(shí)現(xiàn)打印彩色字符串的方法詳解

    Python實(shí)現(xiàn)打印彩色字符串的方法詳解

    print?也許是我們?cè)谑褂?Python?的時(shí)候用的最多的一種操作,但是經(jīng)常發(fā)現(xiàn)很多人可以打印彩色文本,這種操作是怎么得到的呢?本文就來為大家詳細(xì)講講
    2022-08-08
  • Python 新建文件夾與復(fù)制文件夾內(nèi)所有內(nèi)容的方法

    Python 新建文件夾與復(fù)制文件夾內(nèi)所有內(nèi)容的方法

    今天小編就為大家分享一篇Python 新建文件夾與復(fù)制文件夾內(nèi)所有內(nèi)容的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • Python PyInstaller庫基本使用方法分析

    Python PyInstaller庫基本使用方法分析

    這篇文章主要介紹了Python PyInstaller庫基本使用方法,結(jié)合實(shí)例形式分析了Python PyInstaller庫的功能、安裝及相關(guān)使用注意事項(xiàng),需要的朋友可以參考下
    2019-12-12
  • Python環(huán)境下安裝PyGame和PyOpenGL的方法

    Python環(huán)境下安裝PyGame和PyOpenGL的方法

    這篇文章主要介紹了Python環(huán)境下安裝PyGame和PyOpenGL的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Django添加bootstrap框架時(shí)無法加載靜態(tài)文件的解決方式

    Django添加bootstrap框架時(shí)無法加載靜態(tài)文件的解決方式

    這篇文章主要介紹了Django添加bootstrap框架時(shí)無法加載靜態(tài)文件的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • pandas string轉(zhuǎn)dataframe的方法

    pandas string轉(zhuǎn)dataframe的方法

    下面小編就為大家分享一篇pandas string轉(zhuǎn)dataframe的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • Python中json文件和jsonl文件的區(qū)別小結(jié)

    Python中json文件和jsonl文件的區(qū)別小結(jié)

    本文主要介紹了JSON和JSONL兩種文件格式的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • pytorch?tensor內(nèi)所有元素相乘實(shí)例

    pytorch?tensor內(nèi)所有元素相乘實(shí)例

    這篇文章主要介紹了pytorch?tensor內(nèi)所有元素相乘實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • PyMongo進(jìn)行MongoDB查詢和插入操作的高效使用示例

    PyMongo進(jìn)行MongoDB查詢和插入操作的高效使用示例

    這篇文章主要為大家介紹了PyMongo進(jìn)行MongoDB查詢和插入操作的高效使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • python生成requirements.txt文件的兩種方法

    python生成requirements.txt文件的兩種方法

    requirements.txt 文件是項(xiàng)目的依賴包及其對(duì)應(yīng)版本號(hào)的信息列表,本文主要介紹了python生成requirements.txt文件的兩種方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-12-12

最新評(píng)論

青岛市| 宁明县| 安乡县| 肇州县| 海兴县| 名山县| 谢通门县| 亳州市| 灵宝市| 吴旗县| 龙井市| 嵩明县| 景宁| 杭州市| 洞口县| 松溪县| 祁阳县| 雷波县| 腾冲县| 乌什县| 巴里| 麻江县| 固原市| 明星| 吴桥县| 三原县| 高清| 广平县| 房产| 长寿区| 黄龙县| 浦城县| 和硕县| 高陵县| 兴国县| 宁海县| 桦川县| 古田县| 漳州市| 肥东县| 河西区|