Pythonで競プロするときの知識メモ2（文字列）

## 1. はじめに
Python[^1]でAtCoderを始めたので、覚えておきたいと思ったことをメモしていきます。
基本的には自分用ですが、Pythonで競プロを始める方の参考になればという気持ちも少しだけあります。

今回は文字列についてです。

## 2. 基本的な文字列の操作
Pythonの文字列はimuutable（= 元のデータが変更されない）です。
元の文字列に対して何らかの操作をした場合、操作後の文字列が新たに生成されます。

### 長さの取得
[len関数](https://docs.python.org/ja/3.11/library/functions.html#len)を使います。

```
a = "abcde"
n = len(a)  # 結果 n: 5
```

### 文字列の結合・繰り返し
結合には加算演算子(+)、繰り返しは乗算演算子(*)を使います。（[参考](https://docs.python.org/ja/3.11/library/operator.html#mapping-operators-to-functions)）

```
a = "abcde"
b = "vw"

# 結合 -> 結果 s: "abcdevw"
s = a + b

# 繰り返し -> 結果 t: "vwvwvwvw"
t = b * 4
```

### 指定した部分文字列の数をカウント
[count関数](https://docs.python.org/ja/3.11/library/stdtypes.html#str.count)を使います。

```
a = "abaacda"
b = "xyzzxyzxyy"

# 変数aに代入した文字列の中に"a"がいくつあるか -> 結果 n: 4
n = a.count("a")

# 変数bに代入した文字列の中に"xy"がいくつあるか -> 結果 m:3
m = b.count("xy")
```

### 大文字 ⇔ 小文字の変換
[upper関数](https://docs.python.org/ja/3.11/library/stdtypes.html#str.upper)や[lower関数](https://docs.python.org/ja/3.11/library/stdtypes.html#str.lower)を使います。

```
a = "abcXYZ"

# 大文字に変換 -> 結果 s: "ABCXYZ"
s = a.upper()

# 小文字に変換 -> 結果 t: "abcxyz"
t = a.lower()
```

### 数値を文字列に変換
[strクラスのコンストラクタ](https://docs.python.org/ja/3.11/library/stdtypes.html#str)を使います。

```
n = 123
m = 2.3

s = str(n)  # 結果 s: "123"
t = str(m)  # 結果 m: "2.3"
```

### 指定した文字で分割
[split関数](https://docs.python.org/ja/3.11/library/stdtypes.html#str.split)を使います。

```
a = "123.456.789"

# "."で分割 -> 結果 l: ["123", "456", "789"]
l = a.split(".")
```

### 指定した部分文字列を取得
#### n文字目を取得する
りストと同じようにn文字目を参照できます。（先頭は0文字目です）

```
a = "abcdef"

# 先頭を0文字目として、2文字目を取得 -> 結果 s: "c"
s = a[2]

# 末尾の文字を取得 -> 結果 t: "f"
t = a[-1]
```

ただし、リストと違い変更はできません。

```
a = "abcdef"
b = ["a", "b", "c", "d", "e", "f"]

# エラー -> TypeError: 'str' object does not support item assignment
a[2] = "x"

# 配列はn番目の要素の変更ができる -> 結果: ["a", "b", "x", "d", "e", "f"]
b[2] = "x"
```

#### n文字目からm文字目までを取得する。
[スライス構文](https://docs.python.org/ja/3.11/library/functions.html#slice)を使います。

```
a = "abcdef"

# a[start:stop] で start から stop の手前までを取得する
# stopの要素は取得しないことに注意

s = a[1:4]  # 結果 s: "bcd"
```

## 3. 知っておくと便利そうなこと
### 文字列定数
stringモジュールには[文字列定数](https://docs.python.org/ja/3.11/library/string.html#string-constants)がいくつか用意されています。

```
# stringモジュールのimportが必要
import string

# 結果 lowerAlphabets: "abcdefghijklmnopqrstuvwxyz"
lowerAlphabets = string.ascii_lowercase 

# 結果 upperAlphabets: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
upperAlphabets = string.ascii_uppercase
```

### フォーマット済み文字列リテラル
[f-string](https://docs.python.org/ja/3.11/tutorial/inputoutput.html#tut-f-strings)を使って文字列のフォーマットが簡単にできます。

```
a = 12.3456789
b = 12

# 小数点以下4桁目が四捨五入される -> 結果: 小数点以下3桁目まで表示 12.346
print(f'小数点以下3桁目まで表示 {a:.3f}')

# 結果: 左を0で埋めて5桁で表示 00012
print(f'左を0で埋めて5桁で表示 {b:05}')
```

### 文字列Tが文字列Sの部分文字列かどうかの判定
[in演算子](https://docs.python.org/ja/3.11/reference/expressions.html#in)で判定できます。
文字列S, Tに対して、TがSの部分文字列かどうかの判定は`T in S`となります。

計算量は O(|S| + |T|) と考えて良さそうです。（[参考](https://atcoder.jp/contests/abc230/editorial/3001)）

```
S = "abcdefgh"
T1 = "cde"
T2 = "bde"

print(T1 in S)  # 結果: True
print(T2 in S)  # 結果: False
```

以上です。
最後まで読んでいただきありがとうございました。

## 参考資料
* [Pythonドキュメント](https://docs.python.org/ja/3.11/library/intro.html)
* [アルゴリズム実技検定 公式テキスト エントリー ~ 中級編](https://www.amazon.co.jp/%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E5%AE%9F%E6%8A%80%E6%A4%9C%E5%AE%9A-%E5%85%AC%E5%BC%8F%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC-%E4%B8%AD%E7%B4%9A%E7%B7%A8-Compass-Books%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/483997277X)
* [Pythonで競プロやるときによく書くコードをまとめてみた](https://qiita.com/y-tsutsu/items/aa7e8e809d6ac167d6a1)

## その他の知識メモ

* [Pythonで競プロするときの知識メモ1（標準入出力）](https://qiita.com/tanakasoboro/items/dcb51c1db5eb53defa4d)

[^1]: 使用しているPythonのバージョンは`3.11.9`です。（2024/11/02現在）