🪐 L2: 木星軌道站

B1: 木星加密通訊:進階字串與字元操作

⏱️ 預計時間:3-4 小時 🎯 目標級分:3 級分 📊 難度:⭐⭐⭐☆☆

🚀 任務背景

歡迎來到木星軌道站!由於距離地球超過 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}%")

🔍 程式碼解說

關鍵技術點

  1. 字元運算的數學原理
   # 將 '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'
   
  1. 為什麼要用 % 26?
  2. 確保結果在 0-25 範圍內
  3. 例如:'Z' + 1 = 'A'(循環)
   # 'Z' 的位置是 25
   (25 + 1) % 26 = 0  # 回到 'A'
   
  1. 字串拼接的效能陷阱
   # ❌ 慢速: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)  # 只創建一次
   
  1. 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. 兩部分交錯合併:第1個字元來自第一部分,第2個字元來自第二部分,依此類推
  3. 如果兩部分長度不同,較長部分的剩餘字元直接附加在最後

你的任務是解碼這段訊息。

輸入格式:
  • 一行字串,長度不超過 100
解碼規則:
  • 奇數位置(1, 3, 5, ...)的字元屬於第一部分
  • 偶數位置(2, 4, 6, ...)的字元屬於第二部分
輸入範例 1:
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("❌ 解碼失敗:這不是有效的交錯編碼")

解答說明

  1. 字串切片的步進參數
   s = "ABCDEFGH"
   #    01234567
   
   s[0::2]  # "ACEG" - 從索引 0 開始,每次跳 2
   s[1::2]  # "BDFH" - 從索引 1 開始,每次跳 2
   
  1. 交錯重建邏輯
   # 假設 part1 = "ABC", part2 = "XY"
   # 重建過程:
   # i=0: 加入 A, 加入 X → "AX"
   # i=1: 加入 B, 加入 Y → "AXBY"
   # i=2: 加入 C, part2 已結束 → "AXBYC"
   
  1. 邊界處理
   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) - 創建新字串

---

🎉

訓練完成!

恭喜你完成 加密通訊與字串處理 訓練!