B1: 木星加密通訊:進階字串與字元操作
任務背景
歡迎來到木星軌道站!由於距離地球超過 6 億公里,通訊延遲長達 40 分鐘。為了確保通訊安全,所有訊息都必須經過加密處理。作為通訊官,你需要掌握字串處理和字元編碼技術。
在這個訓練模組中,你將學習:- 字串的不可變性及其影響
- 字元與數字的轉換(ASCII/Unicode)
- 高效的字串操作方法
- 字串格式化技巧
知識點說明
字串的不可變性(Immutability)
⚠️ 核心概念:Python 中的字串是不可變的!
message = "HELLO"
# message[0] = "J" # ❌ 錯誤!無法修改字串
# ✅ 正確:創建新字串
message = "J" + message[1:] # "JELLO"
這意味著每次「修改」字串,實際上都是創建一個新的字串物件。
字元編碼:ord() 和 chr()
每個字元都有一個對應的數字編碼:
# 字元 → 數字
print(ord('A')) # 65
print(ord('Z')) # 90
print(ord('a')) # 97
# 數字 → 字元
print(chr(65)) # 'A'
print(chr(90)) # 'Z'
常用字串方法
| 方法 | 功能 | 範例 |
|------|------|------|
| split() | 分割字串 | "a b c".split() → ['a', 'b', 'c'] |
| join() | 連接字串 | "-".join(['a','b']) → "a-b" |
| strip() | 移除空白 | " hi ".strip() → "hi" |
| replace() | 替換子串 | "cat".replace('c','b') → "bat" |
| upper() | 轉大寫 | "hello".upper() → "HELLO" |
| lower() | 轉小寫 | "HELLO".lower() → "hello" |
字串切片(Slicing)
text = "JUPITER"
# 0123456
print(text[0:3]) # "JUP" (索引 0,1,2)
print(text[2:]) # "PITER" (從索引 2 到結尾)
print(text[:4]) # "JUPI" (從開頭到索引 3)
print(text[::2]) # "JPTE" (每隔一個字元)
print(text[::-1]) # "RETIPUJ" (反轉字串)
範例程式碼
範例 1:凱薩密碼加密系統
import sys
# 任務:使用凱薩密碼加密訊息(字母位移)
message = sys.stdin.readline().strip()
shift = int(sys.stdin.readline())
encrypted = ""
for char in message:
if char.isupper(): # 大寫字母
# 將字母轉為 0-25,位移後再轉回字母
new_pos = (ord(char) - ord('A') + shift) % 26
encrypted += chr(ord('A') + new_pos)
elif char.islower(): # 小寫字母
new_pos = (ord(char) - ord('a') + shift) % 26
encrypted += chr(ord('a') + new_pos)
else:
encrypted += char # 非字母字元保持不變
print(f"原始訊息:{message}")
print(f"加密訊息:{encrypted}")
範例 2:訊息解析器
import sys
# 任務:解析太空船狀態報告
# 格式:"SHIP-001:FUEL-75:OXYGEN-90:SPEED-25000"
report = sys.stdin.readline().strip()
# 分割報告
parts = report.split(':')
# 解析每個部分
ship_id = parts[0].split('-')[1]
fuel = int(parts[1].split('-')[1])
oxygen = int(parts[2].split('-')[1])
speed = int(parts[3].split('-')[1])
print(f"太空船編號:{ship_id}")
print(f"燃料:{fuel}%")
print(f"氧氣:{oxygen}%")
print(f"速度:{speed} km/h")
# 狀態判斷
if fuel < 30 or oxygen < 30:
print("⚠️ 警告:資源不足!")
else:
print("✅ 系統正常")
範例 3:高效字串拼接
import sys
# 任務:生成太空站日誌報告
n = int(sys.stdin.readline())
# ❌ 低效方法(每次都創建新字串)
report_slow = ""
for i in range(n):
report_slow += f"Day {i+1}: Mission ongoing\n"
# ✅ 高效方法(使用列表收集,最後一次性連接)
report_fast = []
for i in range(n):
report_fast.append(f"Day {i+1}: Mission ongoing")
final_report = '\n'.join(report_fast)
print(final_report)
範例 4:字串反轉與回文檢測
import sys
# 任務:檢查密碼是否為回文(正反讀都一樣)
password = sys.stdin.readline().strip()
# 方法 1:使用切片反轉
reversed_password = password[::-1]
if password == reversed_password:
print(f"✅ '{password}' 是回文密碼")
else:
print(f"❌ '{password}' 不是回文密碼")
# 方法 2:雙指標法(更節省空間)
left = 0
right = len(password) - 1
is_palindrome = True
while left < right:
if password[left] != password[right]:
is_palindrome = False
break
left += 1
right -= 1
print(f"雙指標檢測結果:{is_palindrome}")
範例 5:DNA 序列分析
import sys
# 任務:分析 DNA 序列中各鹼基的數量
dna_sequence = sys.stdin.readline().strip().upper()
# 統計每種鹼基
count_A = dna_sequence.count('A')
count_T = dna_sequence.count('T')
count_G = dna_sequence.count('G')
count_C = dna_sequence.count('C')
total = len(dna_sequence)
print(f"DNA 序列長度:{total}")
print(f"A (腺嘌呤):{count_A} ({count_A/total*100:.1f}%)")
print(f"T (胸腺嘧啶):{count_T} ({count_T/total*100:.1f}%)")
print(f"G (鳥嘌呤):{count_G} ({count_G/total*100:.1f}%)")
print(f"C (胞嘧啶):{count_C} ({count_C/total*100:.1f}%)")
# 檢查 GC 含量(重要的生物指標)
gc_content = (count_G + count_C) / total * 100
print(f"\nGC 含量:{gc_content:.1f}%")
程式碼解說
關鍵技術點
- 字元運算的數學原理
# 將 'A' 位移 3 變成 'D'
char = 'A'
shift = 3
# 步驟 1:轉為相對位置 (0-25)
pos = ord(char) - ord('A') # 0
# 步驟 2:位移並取模(處理超出範圍)
new_pos = (pos + shift) % 26 # 3
# 步驟 3:轉回字元
new_char = chr(ord('A') + new_pos) # 'D'
- 為什麼要用 % 26?
- 確保結果在 0-25 範圍內
- 例如:'Z' + 1 = 'A'(循環)
# 'Z' 的位置是 25
(25 + 1) % 26 = 0 # 回到 'A'
- 字串拼接的效能陷阱
# ❌ 慢速:O(N²) 時間複雜度
result = ""
for i in range(10000):
result += str(i) # 每次都創建新字串!
# ✅ 快速:O(N) 時間複雜度
parts = []
for i in range(10000):
parts.append(str(i))
result = ''.join(parts) # 只創建一次
- f-string 的強大功能
name = "Jupiter"
distance = 778500000
# 基本格式化
print(f"距離:{distance} km")
# 數字格式化
print(f"距離:{distance:,} km") # 778,500,000 km
print(f"距離:{distance:.2e} km") # 7.79e+08 km
# 對齊
print(f"{name:>10}") # 右對齊,寬度 10
Quiz: 外星訊號解碼
題目:交錯字串解碼
木星軌道站收到一段外星訊號,經過分析發現這是一段「交錯編碼」的訊息。編碼規則如下:
- 原始訊息被分成兩部分
- 兩部分交錯合併:第1個字元來自第一部分,第2個字元來自第二部分,依此類推
- 如果兩部分長度不同,較長部分的剩餘字元直接附加在最後
你的任務是解碼這段訊息。
輸入格式:- 一行字串,長度不超過 100
- 奇數位置(1, 3, 5, ...)的字元屬於第一部分
- 偶數位置(2, 4, 6, ...)的字元屬於第二部分
HWEOLRLLOD
輸出範例 1:
第一部分:HELLO
第二部分:WORLD
解碼失敗:這不是有效的交錯編碼
(因為兩部分無法正確交錯回原字串)
輸入範例 2:
JSUEPCIOTNER
輸出範例 2:
第一部分:JUPITER
第二部分:SECTOR
💡 提示
- 使用字串切片的步進功能:
s[::2]取奇數位置,s[1::2]取偶數位置 - Python 的索引從 0 開始,所以
s[0]是第 1 個字元
---
Quiz 解答
import sys
# 讀取編碼訊息
encoded = sys.stdin.readline().strip()
# 解碼:分離奇數和偶數位置的字元
# 注意:Python 索引從 0 開始
# s[0::2] 取索引 0, 2, 4, ... (第 1, 3, 5, ... 個字元)
# s[1::2] 取索引 1, 3, 5, ... (第 2, 4, 6, ... 個字元)
part1 = encoded[0::2] # 奇數位置
part2 = encoded[1::2] # 偶數位置
print(f"第一部分:{part1}")
print(f"第二部分:{part2}")
# 驗證:重新交錯看是否能還原
reconstructed = ""
max_len = max(len(part1), len(part2))
for i in range(max_len):
if i < len(part1):
reconstructed += part1[i]
if i < len(part2):
reconstructed += part2[i]
if reconstructed == encoded:
print("✅ 解碼成功!")
else:
print("❌ 解碼失敗:這不是有效的交錯編碼")
解答說明
- 字串切片的步進參數
s = "ABCDEFGH"
# 01234567
s[0::2] # "ACEG" - 從索引 0 開始,每次跳 2
s[1::2] # "BDFH" - 從索引 1 開始,每次跳 2
- 交錯重建邏輯
# 假設 part1 = "ABC", part2 = "XY"
# 重建過程:
# i=0: 加入 A, 加入 X → "AX"
# i=1: 加入 B, 加入 Y → "AXBY"
# i=2: 加入 C, part2 已結束 → "AXBYC"
- 邊界處理
if i < len(part1): # 確保不超出範圍
reconstructed += part1[i]
這樣可以處理兩部分長度不同的情況
進階版本:使用 zip_longest
from itertools import zip_longest
# 更優雅的交錯方法
reconstructed = ""
for c1, c2 in zip_longest(part1, part2, fillvalue=''):
reconstructed += c1 + c2
print(reconstructed)
效能分析
- 時間複雜度:O(N) - N 是字串長度
- 空間複雜度:O(N) - 需要儲存分離後的兩部分
- 切片操作:O(N) - 創建新字串
---
訓練完成!
恭喜你完成 加密通訊與字串處理 訓練!