# Python字串的基本操作與進階應用(3)
### ***這東西你可以不會,但會了更好***
### ***by 幻宇***
適當的字串操作,能幫助使用者更好的理解程式要表達的內容,有時也能讓程式碼變得更加簡潔,在這裡我們將介紹幾種常用的字串操作方式
- 字串運算子和特殊用法
- 內建函數
- ANSI控制碼
我們的重點會放在內建的部分,ANSI控制碼只會大概提一下
## 字串運算子和特殊用法
字串運算子在分類上並不屬於運算子,Python的字串運算子行為是由類別方法來控制的,而不是由語法層級直接支持,但有些運算子也能當成字串運算子來用
### `+`:連接兩個字串
```python
a = "hello"
b = "world"
print(a + " " + b)
# hello world
```
### `*`:將字串重複輸出指定次數
```python
print("hello" * 3)
# hellohellohello
```
### `in`:判斷一個字串是否包含於另一個字串中,輸出為布林值
```python
print("ll" in "hello")
# True
print("le" in "hello")
# False
```
### `not in`:與`in`相反
```python
print("ll" not in "hello")
# Flase
print("le" not in "hello")
# True
```
### `[]`:索引運算子(Indexing Operator)功能是透過索引訪問字串的單個字元(第一個字符代碼為0第二為1以此類推)
```python
print("hello"[0])
# h
print("hello"[2])
# l
```
### `[m:n]`:選取從第 m 個字符到第 n 個字符之間的所有字元(包含第 m 個字符但不包含第 n 個),若 m 省略不寫則預設為第0個字元,n 省略不寫則預設為最後一個字元
```python
print("hello world"[2:8])
# llo wo
print("hello world"[6:]) #選取從第 n 個字符後的所有字元(包含第 n 個字符)
# world
print("hello world"[:5]) #選取從第 n 個字符前的所有字元(不包含第 n 個字符)
# hello
```
### `[m:n:p]`:從第 m 個字符到第 n 個字符之間,表示每隔 p 個字元取一次(間隔值 p-1 且不包含第 n 個字元,另外若 p 為負數則從右側開始),若 m 省略不寫則預設為第0個字元,n 省略不寫則預設為最後一個字元(但此時若第 n 個字元符合條件則會輸出)
```python
print("hello world"[0:10:2]) #取0、2、4、6、8
# hlowr
print("hello world"[0::2] )#取0、2、4、6、8、10
# hlowrd
print("hello world"[:10:2]) #取0、2、4、6、8
# hlowr
print("hello world"[::2]) #取0、2、4、6、8、10
# hlowrd
print("hello world"[10:0:-2]) #取10、8、6、4、2
# drwol
```
##### 補充:在前面的兩個運算子中我們常會看到一個`:`而他的名子是切片運算子(Slicing Operator)
### `%`:格式化運算子(Formatting Operator),`%`後面會接一個格式化字元來指定如何顯示相應的值,而值需用`%`來給予,當然,也可以直接放變數,下面會先列出常見的幾個格式化字元再來舉例
- `%s`:字串
- `%d`:整數
- `%f`:浮點數
- `%x`:整數的十六進位格式
- `%o`:整數的八進位格式
- `%e`:科學記數法
```python
print("My name is %s" %"huanyu")
# My name is huanyu
a = huanyu
print("My name is %s" % a)
# My name is huanyu
print("123%d" % 4)
# 1234
print("height:%f" % 169.9)
# height:169.900000
print("Hex: %x" % 255)
# Hex: ff
print("Oct: %o" % 8)
# Oct: 10
print("Sci: %e" % 1234.5678)
# Sci: 1.234568e+03
name = "Huanyu"
age = 17
print("My name is %s and I am %d years old." % (name, age))
# My name is Huanyu and I am 17 years old.
```
### `str.format`:在字串中插入變數、數字或其他資料,並根據需求進行格式化顯示。它比舊式的`%`格式化方式更強大且靈活,並且支援更多的自定義控制。使用大括號`{}`作為佔位符,然後通過`format()`方法將具體的數值或變數插入,嚴格來說他其實也算是內建函數
```python
name = "Huanyu"
age = 17
print("My name is {} and I am {} years old.".format(name, age))
# My name is Huanyu and I am 17 years old.
```
可以給佔位符指定位置索引,從而更靈活地控制插入順序。
```python
name = "Huanyu"
age = 17
print("My name is {0} and I am {1} years old. {0} is learning Python.".format(name, age))
# My name is Huanyu and I am 17 years old. huanyu is learning Python.
```
除了這些功能以外,他還可以支援各種數字格式化,包括小數位數控制、百分比、十六進制等
### `f"{}`:全名是f-string,用途和前兩個差不多但更為直觀,能直接將變數放入字串中,一樣是使用大括號`{}`作為佔位符,但括號內直接放變數
```python
name = "Huanyu"
age = 17
print(f"My name is {name} and I am {age} years old.")
# My name is Huanyu and I am 17 years old.
```
### `\`跳脫字元:
- `\`:用來表示後面的字元有與其本質不同的用途
- `\n`:換行符號
- `\t`:會在輸出時插入一個水平跳位,也就是一個tab
```python
print("\"")#"用來表示字串,正常來說是無法輸出的
# "
print("Hello World\n")
# Hello World
#
print("Hello\tWorld")
# Hello World
```
### 三重引號:直接照內容的格式輸出
```python
print("""
hello
world
""")
#
# hello
# world
#
```
### 控制小數位數
```python
n = 3.333
print(f"{n:.2f}")
# 3.33
```
## 內建函數
有關於字串的內建函數有很多,在這裡我們只會挑一些常用的來講
### `print()`:這應該是我們最熟悉的內建函數了,但他除了輸出純文字以外還可以在加入其他參數
- `sep`:定義多個項目之間的分隔符,預設為空格
```python
print("Hello", "World", sep="-")
# Hello-World
```
- `end`:定義輸出結尾的字符,預設為換行符`\n`,這就是為什麼print完會自動換行的原因
```python
print("Hello", end="!")
# Hello!
```
- `file`:定義輸出的目標,預設為`sys.stdout`,也就是終端機,也可以設定為檔案或其他可輸出的地方
```python
with open("output.txt", "w") as f:#這裡是開啟檔案的部分,之後會講
print("Hello, file!", file=f) # 將內容寫入到檔案
```
- `flush`:在 Python 中,當你使用`print()`或其他輸出方法時,資料通常不會立即顯示或寫入到指定的目標(例如螢幕或檔案),而是暫時儲存在一個「緩衝區」中,等到緩衝區累積到一定程度,或程式結束時,這些資料才會被寫入目標位置,預設為`False`,`flush=True` 的作用是強制 Python 馬上清空這個緩衝區,把資料立即寫入或顯示出來,而不等待緩衝區滿或程式結束。例如,在需要即時更新輸出的情況下(如顯示進度條或即時監控資訊),這個參數會很有用
```python
print("即時輸出", flush=True)
# 即時輸出
```
### `len()`返回字串的長度
```python
print(len("12345"))
# 5
```
### `str()`:將型別轉換成字串,通常用於非字串內容作字串處理時
```python
print(len(str(12345)))
# 5
```
### `upper()`:將字串中的所有字母轉為大寫
```python
a = "hello"
print(a.upper())
# HELLO
```
### `title()`:將字串轉為標題格式(每個單字的第一個字母大寫)
```python
a = "hello world"
print(a.title())
# Hello World
```
### `swapcase()`:將字串中的大寫字母轉為小寫,小寫字母轉為大寫
```python
a = "Hello World"
print(a.swapcase())
# hELLO wORLD
```
### `capitalize()`:將字串的第一個字母轉為大寫,其他字母轉為小寫
```python
a = "hello WORLD"
print(a.capitalize())
# Hello world
```
### `lower()`:將字串中的所有字母轉為小寫
```python
a = "HELLO"
print(a.lower())
# hello
```
### `casefold()`:將字串轉為小寫,功能類似`lower()``,但處理更多語言中的大小寫區分
```python
a = "Groß"
print(a.casefold())
# gross
```
### `isalnum()`:如果字串只包含字母和數字且非空,返回`True`
```python
a = "abc123"
print(a.isalnum())
# True
print("abc!".isalnum())
# False
```
### `isalpha()`:如果字串只包含字母且非空,返回`True`
```python
a = "hello"
print(a.isalpha())
# True
print("hello123".isalpha())
# False
```
### `isdecimal()`:如果字串只包含純十進制數字(0~9)且非空,返回`True`
```python
a = "12345"
print(a.isdecimal())
# True
print("123.45".isdecimal())
# False(小數點)
print("2²".isdecimal())
# False(上標數字)
```
### `isdigit()`:如果字串只包含數字字符(所有類型的數字字符但不包含羅馬數字)且非空,返回`True`
```python
a = "12345"
print(a.isdigit())
# True
print("123.45".isdigit())
# False
print("2²".isdigit())
# True(上標數字)
print("Ⅲ".isdigit())
# False(羅馬數字)
```
### `isnumeric()`:如果字串只包含數字字符(所有類型的數字字符)且非空,返回`True`
```python
a = "12345"
print(a.isnumeric())
# True
print("²³".isnumeric())
# True (上標數字)
print("⅕".isnumeric())
# True (分數字符)
print("Ⅲ".isnumeric())
# True (羅馬數字)
```
### `islower()`:如果字串中的所有字母都是小寫,返回`True`
```python
a = "hello"
print(a.islower())
# True
print("Hello".islower())
# False
```
### `isspace()`:如果字串只包含空白字符,返回`True`
```python
a = " "
print(a.isspace())
# True
print("abc".isspace())
# False
```
### `istitle()`:如果字串是標題格式(每個單字的第一個字母大寫),返回 `True`
```python
a = "Hello World"
print(a.istitle())
# True
print("hello world".istitle())
# False
```
### `isupper()`:如果字串中的所有字母都是大寫,返回`True`
```python
a = "HELLO"
print(a.isupper())
# True
print("Hello".isupper())
# False
```
### `count(sub, start, end)`:返回子字串在字串中出現的次數,
- `sub`:子字串
- `start`:由第幾個字開始,預設為0,可以省略
- `end`:到第幾個字結束,結束的那個字不會偵測,預設為最後一個字之後,可以省略
```python
a = "hello world"
print(a.count('o'))
# 2
print(a.count('o', 0, 5))
# 1
```
### `replace(old, new, count)`:將字串中原有的內容替換為指定的內容
- `old`:要替換掉的內容
- `new`:要替換成的內容
- `count`:替換次數,可省略
```python
a = "hello world"
print(a.replace("o", "0"))
# hell0 w0rld
print(a.replace("o", "0", 1))
# hell0 world
```
### `rfind(sub, start, end)`:返回子字串在字串中最後一次出現的索引位置。如果找不到,返回 -1
- `sub`:子字串
- `start`:由第幾個字開始,預設為0,可以省略
- `end`:到第幾個字結束,結束的那個字不會偵測,預設為最後一個字之後,可以省略
```python
a = "hello world"
print(a.rfind("o"))
# 7
print(a.rfind("z"))
# -1
print(a.rfind("o", 0, 4))
# -1
```
### `endswith(suffix, start, end)`:如果字串以指定的子字串結尾,返回`True`,這在確認副檔名時很有用
- `suffix`:子字串
- `start`:由第幾個字開始,預設為0,可以省略
- `end`:到第幾個字結束,結束的那個字不會偵測,預設為最後一個字之後,可以省略
```python
a = "hello.txt"
print(a.endswith(".txt"))
# True
print(a.endswith(".jpg"))
# False
```
### `partition(sep)`:將字串分割為三部分:分隔符前、分隔符、分隔符後
- `sep`:分割符
```python
a = "hello-world"
print(a.partition("-"))
# ('hello', '-', 'world')
before, separator, after = a.partition("-")
print(before)
# hello
print(separator)
# -
print(after)
# world
```
### `split(sep, max)`:功能與`partition()`相同,但可分割多次
- `sep`:分割符,若不設預設為空格,且輸出時分割符不會輸出
- `max`:分割次數,若不設則預設無上限
```python
a = "abc 12345"
b,c = a.split()
print(b)
# abc
print(c)
# 12345
a,b = input().split()
#輸入1 2
print(a,b)
# 1 2
```
### `expandtabs(tabsize)`:將字串中的`\t`替換為空格,間隔由`tabsize`指定,默認為八個空格也就是兩個`Tab`
```python
a = "a\tb\tc"
print(a.expandtabs(4))
# a b c
```
### `encode(encoding, errors)`:將字串編碼為指定編碼,這在處理國際化文本時常會用到
- `encoding`:編碼格式,預設為`utf-8`
- `error`:這個參數指定在遇到無法編碼的字符時應如何處理
- `strict`:默認的錯誤處理方式,會引發`UnicodeEncodeError`錯誤
- `ignore`:忽略無法編碼的字符
- `replace`:將無法編碼的字符替換為`?`
- `backslashreplace`:將無法編碼的字符以反斜線序列表示(例如,`\uXXXX`形式)
```python
a = "hello"
print(a.encode(encoding='utf-8', errors='strict'))
# b'hello'
print("你好,世界!".encode(encoding='utf-8', errors='strict'))
# b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c!'
```
## ANSI控制碼
在 Python 中,ANSI 控制碼(ANSI Escape Codes)主要用來控制終端(terminal)中的文字顯示,包含文字的顏色、背景色以及其他格式(例如粗體、閃爍等)。這些控制碼在字串中以特殊的轉義序列形式出現,通常以`\033` 開頭,接著是一些控制碼和數字組合來實現不同的效果
### ANSI 控制碼的結構
- **轉義符號:**`\033`或`\x1b`是控制碼的起始符號(`\033`是十進制的 ESC 字符,`\x1b`是它的十六進制表示)
- **方括號:**`[`
- **參數:** 數字(可以是一個或多個數字,中間用`;`分隔)
- **結尾符:** 一個字母,用來表示具體的效果
### 基本控制類型
- **文字顏色**
- `\033[30m`:黑色
- `\033[31m`:紅色
- `\033[32m`:綠色
- `\033[39m`:重設
- 具體有哪些可以自己試試看
- **背景顏色**
- `\033[40m`:黑色背景
- `\033[41m`:紅色背景
- `\033[42m`:綠色背景
- `\033[49m`:重設
- 具體有哪些可以自己試試看
- **文字樣式**
- `\033[1m`:粗體字
- `\033[4m`:加底線
- `\033[7m`:反轉(文字和背景顏色對調)
- `\033[0m`:重設
- 具體有哪些可以自己試試看
- **256色控制**
- `\033[38;5;{n}m`:控制文字顏色
- `\033[48;5;{n}m`:控制背景顏色
- `{n}`是 0-255 的顏色編號
### 範例
```python
# 簡單的 ANSI 控制碼範例
print("\033[1;31m這是一段紅色粗體文字\033[0m")
print("\033[32m這是一段綠色文字\033[0m")
print("\033[4;34m這是一段藍色帶下底線的文字\033[0m")
print("\033[7;33m這是一段反轉的黃色文字\033[0m")
# 使用256色模式
print("\033[38;5;82m這是256色模式中的綠色\033[0m")
print("\033[48;5;196m這是256色模式中的紅色背景\033[0m")
```
大家可以運行看看,要記得自己試著寫的時候結尾一定要記得加`\033[0m`不然的話顏色設定會一直維持下去
### 終端機控制
- **清除終端機**
- `\033c`:重置終端(清除並重置終端的所有設定)
- `\033[2J`:清除終端(清除並但不重置終端的所有設定,且光標留在原位)
- `\033[H\033[J`:由兩個指令組成,第一個是`\033[H`,它會將光標移動到終端的左上角,第二個是`\033[J`,它會清除從當前光標位置到終端的底部。
- **光標控制**
- `\033[H`:將光標移動到左上角
- `\033[n;mH`:將光標移動到第`n`行,第`m`列
- `\033[nA`:將光標向上移動`n`行
- `\033[nB`:將光標向下移動`n`行
- `\033[nC`:將光標向右移動`n`列
- `\033[nD`:將光標向左移動`n`列
- `\033[s`:保存當前光標位置
- `\033[u`:恢復到之前保存的光標位置
- **清除行內容**
- `\033[K`:清除從光標到行尾的內容。
- `\033[1K`:清除從光標到行首的內容。
- `\033[2K`:清除整行。
- **隱藏/顯示光標**
- `\033[?25l`:隱藏光標
- `\033[?25h`:顯示光標
- **滾動控制**
- `\033[nS`:將終端內容向上捲動`n`行
- `\033[nT`:將終端內容向下捲動`n`行
### 範例
```python
print("\033[s") # 保存當前光標位置
print("\033[10;10H這是位於第10行第10列的文字")
print("\033[u這是恢復後的光標位置")
print("\033c", end="")
print("\033[32m你甚麼都沒看到\033[0m")
```
## 實做練習
凱薩密碼(Caesar Cipher)是古羅馬時期的凱薩大帝所使用的一種簡單加密技術。這種方法將訊息中的每個字母向平移固定的位數(也就是偏移量),從而將原始訊息加密。比如說,若偏移量為3,ABC 會被加密成 DEF
這次的實作練習就是用前面所學到的知識做出一個能加密和解密且偏移量可自由設定,且設定好偏移量後就可以一直重複加密解密而不需重啟(偏移量設定除外)
運行結果範例:
```
這是一個凱薩密碼程式
在這裡可以進行加密和解密
輸入格式:
加密:要加密的內容
範例:
加密:code
解密:要解密的內容
範例:
解密:frgh
程式剛啟動時需設定偏移量
設定完成後若需更改請重啟該程式
另外如果輸入非英文內容該內容將直接輸出
且輸出為全為小寫
請設定偏移量(1-25)3
設定成功,偏移量為3
請輸入要加密或解密的內容
加密:code:12345
結果:frgh:12345
請輸入要加密或解密的內容
解密:frgh:12345
結果:code:12345
請輸入要加密或解密的內容
```
## [下一篇](https://hackmd.io/@Huanyu763/Python基礎資料結構)
## [回到主頁](https://hackmd.io/@Huanyu763/home)