Pythonビルトインの様々な文字列操作

# まえおき

- この記事は執筆中の[やさしくはじめるPythonプログラミング](https://github.com/simon-ritchie/python-novice-book-preview)の本の特定の章の部分抜粋です。
- 入門本なので初心者の方向けです。
- ビルトインの文字列操作関係の章の内容が主になります。
- Qiita記事にマッチしていない箇所（「章」や「ページ」といった単語が使っていたり、改行数が余分だったり、リンクが対応していない等）があるという点はご留意ください。気になる方は↑のリンクの電子書籍版をご利用ください（Githubでダウンロードできます）。
- コメントなどでフィードバックいただいた場合、書籍側にも活用・反映させていただく場合があります。

# 文字列の各操作

前章までで基本的なPythonの操作や型・ビルトイン関数などを学んできました。本章では文字列に対して追加の操作について学んでいきます（前章までである程度操作方法について学んできましたが、他にも大切で便利な操作方法などが色々あるのでそちらを学んでいきます）。

数は多いので全ては覚えなくても、「そういえばこんなものもあった」程度で大丈夫です。必要な時に都度検索して思い出せれば問題ありません。

## 文字列のインデックスとスライス

リストの説明関係のセクションでスライス（リストの特定の範囲の値のみに抽出など）について学びましたが、実は文字列でも同様のスライスを行うことができます。リストの時のように、`[1:3]`といったような括弧と数字・コロンを使ったインデックス範囲の指定で制御することができます。

インデックスの数字は各文字ごとに割り振られます。リストの時と同じく0からスタートとなります。

例えば`Apple`という文字列であれば、以下のようにインデックスが割り振られます。

- 0 → A
- 1 → p
- 2 → p
- 3 → l
- 4 → e

ある種、「文字列（string）は文字（character）を格納したリストのようなもの」とも言えるかもしれません。

実際にリスト的にインデックスへの値の参照をコードを書いて試してみましょう。

まずは特定のインデックスの内容を出力してみます（`[0]`とか`[1]`といった指定をします）。該当する文字単体が出力されることを確認できます。

```py
str_value = 'Apple'
print(str_value[0])
```

コード実行結果の出力内容:

```output
A
```
　

```py
str_value = 'Apple'
print(str_value[1])
```

コード実行結果の出力内容:

```output
p
```
　

続いて「〇〇のインデックス以降××のインデックス未満」というようにスライスで特定範囲の文字列を抽出してみます。リストと同様にコロンの左側の数字が「〇〇のインデックス以降」を表し、コロンの右側の数字が「××のインデックス未満」という条件になります。つまり`[1:4]`と指定すれば、「1以降4未満」という条件（1, 2, 3のインデックスが対象）になり、`Apple`という文字に対して設定すれば`ppl`という部分が抽出できます。

```py
str_value = 'Apple'
print(str_value[1:4])
```

コード実行結果の出力内容:

```output
ppl
```
　

勿論リストのスライスと同様に、コロンの左側の数字だけ指定して「〇〇以降」という条件だけ指定したり、右側の数字だけ指定して「××未満」という条件だけを指定するといった書き方もすることができます。

## 文字列の最初が特定の文字列になっているかどうかを調べる : startswithメソッド

文字列のstartswithメソッドでは、対象の文字列が第一引数に渡された文字列で始まっているかの真偽値を取得することができます。

「〇〇の文字列で始まる」という意味で「starts with 〇〇の文字列」といった英語で書くので、メソッド名はそちらに由来します。

プログラムでは変数名や定数名などで、同じグループの値を統一して特定の文字列から始める書き方がされることが結構あり、プレフィックス（prefix）などとも呼ばれます。`pre`が「前に」といった意味を持ち、「先頭に付けるもの」といったように使われます（その他にも）。

例えば`ITEM_ID_`というプレフィックスを使って定数に`ITEM_ID_〇〇`といったような名前が付けられます。

startswithメソッドではこのようなプレフィックスに対象の文字列がなっているかどうかを調べるのに便利です。後々の章で触れますが、プログラム内の変数名や定数名なども文字列として取得することができるので、特定のプレフィックスだったら処理を行う...といったような制御が可能になります。

使い方は第一引数にプレフィックスを指定すると、TrueかFalseかの真偽値が返却されます。

文字列が指定したプレフィックスで始まっているためTrueが返却されるケース :

```py
str_value = 'FRUIT_ID_APPLE'
print(str_value.startswith('FRUIT_ID_'))
```

コード実行結果の出力内容:

```output
True
```
　

文字列が指定したプレフィックスで始まっていないためFalseが返却されるケース :

```py
str_value = 'FRUIT_ID_APPLE'
print(str_value.startswith('ITEM_ID'))
```

コード実行結果の出力内容:

```output
False
```
　

## 文字列の最後が特定の文字列になっているかどうかを調べる : endswithメソッド

endswithメソッドはstartswithメソッドと似たようなメソッドとなりますが、startswithメソッドが文字列の先頭が対象なのに対してこちらは末尾が対象となります。

末尾の文字列のことはサフィックス（suffix）と言います。

startswithメソッドと同様に、endswithメソッドでも第一引数にサフィックスを指定する形で使います。結果も同様に真偽値で返ってきます。

文字列が指定したサフィックスで終わっているためTrueが返却されるケース :

```py
str_value = 'CAT_NAME'
print(str_value.endswith('_NAME'))
```

コード実行結果の出力内容:

```output
True
```
　

文字列が指定したサフィックスで終わっていないためFalseが返却されるケース :

```py
str_value = 'CAT_AGE'
print(str_value.endswith('_NAME'))
```

コード実行結果の出力内容:

```output
False
```
　

## startswithとendswithメソッドはスライスでも同じようなことはできるけれども...

前のセクションで触れた通り、文字列はスライスを使って特定の範囲の文字列を抽出することができます。例えば以下のようにすると、任意の文字数のプレフィックス部分を取得することができます。

```py
str_value = 'FRUIT_ID_APPLE'
print(str_value[:6])
```

コード実行結果の出力内容:

```output
FRUIT_
```
　

また、後々の章で学びますが、Pythonでは`左辺の値 == 右辺の値`といったように、半角のイコールの記号2つとその左右に任意の値を指定して、もし両辺の値が一致していればTrue、一致していなければFalseとなる書き方ができます。

両辺の値が一致しているためTrueとなるサンプル :

```py
int_value = 100
print(int_value == 100)
```

コード実行結果の出力内容:

```output
True
```
　

両辺の値が一致していないためFalseとなるサンプル :

```py
int_value = 95
print(int_value == 100)
```

コード実行結果の出力内容:

```output
False
```
　

スライスとこの2つのイコールの記号を使うとstartswithメソッドやendswithメソッドででやるような判定と同じことをすることができます。例えば以下のように`[:9]`とスライスで指定すれば先頭の9文字が取得できるのでその9文字を左辺、右辺に文字列で想定しているプレフィクスを指定すればstartswithメソッドを使った時と同じようにTrueもしくはFalseの真偽値を取得することができます。

```py
str_value = 'FRUIT_ID_APPLE'
print(str_value[:9] == 'FRUIT_ID_')
```

コード実行結果の出力内容:

```output
True
```
　

ただし、この書き方は文字数を数え間違えていたり、うっかりスライスの数字の指定を間違えてしまったりすると想定した挙動になってくれません。例えば以下のようなコードは想定した判定になってくれません。

```py
str_value = 'FRUIT_ID_APPLE'
print(str_value[:9] == 'FRUIT_ID')
```

コード実行結果の出力内容:

```output
False
```
　

この書き方だとぱっと見で「どこが間違っているの・・・？」という点は瞬時には分かりづらいですし、コードの内容も読みづらく思えます。プレフィックス（文字の先頭）の比較はまだしもサフィックス（文字の末尾）側はもっとコードが読みづらくなります。

この辺りの間違いやすさなどはPythonのコーディング規約のPEP8でもstartswithやendswithを使うようにと定められています。

> 文字列に特定のプレフィックスやサフィックスがついているかをチェックするには、文字列のスライシングではなく ''.startswith() と ''.endswith() を使いましょう。
>
> startswith() と endswith() を使うと、綺麗で間違いが起こりにくいコードになります:  
> [Python コードのスタイルガイド](https://pep8-ja.readthedocs.io/ja/latest/)

他の人がコードを読んだ時に少し時間をかければしっかりと内容は把握できますが、普段の仕事で時間が限られているので極力コードは「瞬時に内容が把握できる」ものが理想です。

特に理由が無ければ、PEP8に合わせてスライスではなくstartswithなどを使って判定するようにしましょう。

## 文字列内に特定の文字列が含まれる位置を検索する : find, rfind, index, rindexメソッド

このセクションでは文字列のfind, rfind, index, rindexの4つのメソッドについて学びます。findメソッドは頻繁に使いますが、他の3つは比較的必要になるケースが少な目かもしれません。

findメソッドは文字列内に特定の文字列がどこに含まれているのかを調べるのに使います。

使い方は第一引数に検索したい文字列を指定します。返却値には最初に見つかった位置のインデックスが設定されます。リストなどのインデックスと同様に、インデックスの値は0から始まります（1文字目がインデックスの0、2文字目がインデックスの1というようになります）。

例えば以下のコードでは`猫`という文字を検索しています。結果は3が返ってきているので、3のインデックス（4文字目）に`猫`という文字があるということを調べることができます。

```py
str_value = '吾輩は猫である。まだ名は無い。'
print(str_value.find('猫'))
```

コード実行結果の出力内容:

```output
3
```
　

取得できたインデックスの整数（今回は3）を文字列に指定してみると、確かに`猫`という文字と位置が一致していることが確認できます。

```py
str_value = '吾輩は猫である。まだ名は無い。'
print(str_value[3])
```

コード実行結果の出力内容:

```output
猫
```
　

`猫`という文字ではなく`猫である`といったような文字列を指定した場合には、その文字列がスタートするインデックスが返却されます。そのため、今回のサンプルでは`猫`という文字を指定した時と返っているインデックスの整数は同じ値の3となります。

```py
str_value = '吾輩は猫である。まだ名は無い。'
print(str_value.find('猫である'))
```

コード実行結果の出力内容:

```output
3
```
　

検索に指定した文字列が見つからない場合には-1が返却されます。

```py
str_value = '吾輩は猫である。まだ名は無い。'
print(str_value.find('犬'))
```

コード実行結果の出力内容:

```output
-1
```
　

これを利用して、もし-1が返却されるかどうかで「特定の文字列が含まれるかどうか」の判定などにも使うことができます。

第二引数は検索するインデックス範囲の開始値です。例えば4を指定したら「4以降のインデックス範囲の文字列が検索される」挙動になります（省略した場合には先頭のインデクス0から検索が実行されます）。

以下のサンプルでは第二引数に3と4を指定しており、文字列が見つかるかどうかの結果が変わることを確認しています。

該当の文字が見つかるケースのサンプル :

```py
str_value = '吾輩は猫である。'
print(str_value.find('猫', 3))
```

コード実行結果の出力内容:

```output
3
```
　

開始インデックスの影響で該当の文字が見つからないケースのサンプル :

```py
str_value = '吾輩は猫である。'
print(str_value.find('猫', 4))
```

コード実行結果の出力内容:

```output
-1
```
　

第三引数は検索するインデックスの終了値です。省略した場合には最後の文字列まで検索が実行されます。

注意点として、ここで指定した値は「以下」の条件ではなく「未満」の条件となります。そのため3を指定した場合インデックスの3はインデックスの対象に含まれず、2までが検索対象となります。

第三引数に3を指定した結果、検索でヒットしなくなるケースのサンプル :

```py
str_value = '吾輩は猫である。'
print(str_value.find('猫', 0, 3))
```

コード実行結果の出力内容:

```output
-1
```
　

第三引数に4を指定した結果、範囲が4未満となるため3のインデックスの文字がヒットするケースのサンプル :

```py
str_value = '吾輩は猫である。'
print(str_value.find('猫', 0, 4))
```

コード実行結果の出力内容:

```output
3
```
　

---

findメソッドの次はrfindメソッドです。

rfindメソッドはfindメソッドとは逆に文字列の右側から検索を実施します。rは「右側から」という意味でrightのrとなっています。

例えば「吾輩は猫である。吾輩は猫ながら時々考える事がある。」という文字列に対して`猫`という文字を検索した場合、右から検索して最初にヒットしたものの位置が返却値として使われるので、2番目の`猫`の文字の位置が対象となります。

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
print(str_value.rfind('猫'))
```

コード実行結果の出力内容:

```output
11
```
　

注意すべき点として、検索自体は右から実施されるものの、結果のインデックスの番号は左からカウントした通常のインデックスで返却されます。

以前の章のリストで触れた通り、`-1`, `-2`, `-3`, ...とインデックスに指定すればそれぞれ右端の文字、右端から2番目の文字、右端から3番目の文字...といったように文字列の右端を基準としたインデックスによるアクセスもできますが、rfindメソッドでは左端の基準とした通常のインデックスの値が返却されるので通常通りにインデックスを指定すれば該当の文字を取得することができます。

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
index = str_value.rfind('猫')
print(str_value[index])
```

コード実行結果の出力内容:

```output
猫
```
　

第二引数と第三引数はfindメソッドと同じく、検索するインデックス範囲の開始値と終了値（未満）となります。こちらもインデックス番号は右からではなく、通常のインデックスと同様に左からのインデックスの番号が使われます。指定したインデックスの範囲で「右側から」検索されるようになります。

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
print(str_value.rfind('猫', 11))
```

コード実行結果の出力内容:

```output
11
```
　

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
print(str_value.rfind('猫', 12))
```

コード実行結果の出力内容:

```output
-1
```
　

---

indexメソッドはほぼfindメソッドと同様の挙動をします。こちらも文字列を検索して見つかったインデックスの番号を取得する挙動となります。

ただし、findメソッドでは検索した文字列が見つからなかった時には-1が返却されていましたが、indexメソッドでは-1ではなくエラーとなります。

該当する文字列が存在するため、findと同様の挙動をするケースのサンプル :

```py
str_value = '吾輩は猫である。'
print(str_value.index('猫'))
```

コード実行結果の出力内容:

```output
3
```
　

該当する文字列が見つからないためエラーになるケースのサンプル :

```py
str_value = '吾輩は猫である。'
print(str_value.index('犬'))
```

```output
ValueError: substring not found
```

substringは特定の文字列の中の一部分の文字列という意味です。これらのメソッドでは第一引数の検索対象の文字列のことを指します。そのためエラーメッセージは「検索に指定された文字列が見つかりませんでした」といった内容になります。

---

最後のrindexメソッドは名前からも推測できる通り、rfindメソッドのように右から検索が実行され、且つindexメソッドのように検索に指定した文字列が見つからない場合はエラーになる挙動をします。

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
print(str_value.rindex('猫'))
```

コード実行結果の出力内容:

```output
11
```
　

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
str_value.rindex('犬')
```

```output
ValueError: substring not found
```


## 文字列を別の文字列に置き換える : replace, translate, maketransメソッド

このセクションでは文字列の置換について学んでいきます。特定の文字列部分を別の文字列に置き換えたりといった制御が該当します。replace, translate, maketransの3つのメソッドを対象とします。特にreplaceメソッドは頻繁に利用します。

---

まずはreplaceメソッドについてです。replaceメソッドは特定の文字列を検索し、該当する文字列を別の文字列に置換します。

第一引数には検索する文字列、第二引数には置換後の文字列を指定します。例えば文字列の中の「猫」という部分を「犬」に置換したい場合には以下のように書きます。

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
print(str_value.replace('猫', '犬'))
```

コード実行結果の出力内容:

```output
吾輩は犬である。吾輩は犬ながら時々考える事がある。
```
　

第三引数は置換回数の設定です。省略すると検索してヒットした文字列が全て置換されます。1を指定すると1回のみ置換、2を指定すると2回のみ置換といった挙動になります。以下のコードでは第三引数に1を指定しているため、1つ目の「猫」という文字部分のみ置換されています。

```py
str_value = '吾輩は猫である。吾輩は猫ながら時々考える事がある。'
print(str_value.replace('猫', '犬', 1))
```

コード実行結果の出力内容:

```output
吾輩は犬である。吾輩は猫ながら時々考える事がある。
```
　

---

translateとmaketransメソッドは一緒に使います。置換前の文字と置換後の文字の特定の組み合わせのものを指定して、一気に複数の文字の置換を行うことができます。

なお、対象は「1文字のもの」となります。複数の文字列のものには使えないのでreplaceメソッドの方を使いましょう。1文字同士の置換がたくさん必要な場合にはtranslateメソッドを使うことで高速に、且つシンプルなコードで置換を行うことができます。

maketransメソッドはその置換の組み合わせのデータを作るためのメソッドです。文字列のインスタンスでも使えますが、後々触れるクラスを直接指定して利用する方が一般的です（`str.maketrans`という書き方をします）。

メソッド名はmake translation tableという英文に由来します。translationは移転や通訳という意味があり、tableは表という意味を持つので、文字と文字の変換表を作るといった感じの意味合いになります。

maketransメソッドには値の指定方法が「辞書のキーと値で指定する方法」と「第一引数と第二引数の2つのセットで指定する方法」の2つが存在します。

まずは辞書での設定の仕方を見ていきます。maketransメソッドの第一引数に辞書を指定して、キーに置換前の文字、値に置換後の文字を指定します。複数の対象がある場合には複数のキーと値のセットを指定します。

今回は以下のような組み合わせで句読点の文字を置換するコードで試してみます（左が置換前、右が置換後）。

- `、` → `,`
- `。` → `.`

```py
trans_table = str.maketrans(
    {
        '、': ',',
        '。': '.',
    }
)
```

もしくは第一引数に置換前の文字を1文字ずつ順番に設定した文字列（今回の例では`、。`という文字列）を指定し、第二引数に置換後の文字列を1文字ずつ順番に設定した文字列（今回の例では`,.`という文字列）を指定する方法もあります。第一引数と第二引数での文字の順番は一致するように注意してください。こちらの書き方でも辞書を使ったときと同じ挙動になります。

```py
trans_table = str.maketrans('、。', ',.')
```

maketransメソッドで作られたデータを使ってtranslateメソッドを使ってみます。第一引数にmaketransメソッドで作られたデータを指定します。

```py
str_value = 'ニャー、ニャーと試みにやって見たが誰も来ない。'
print(str_value.translate(trans_table))
```

コード実行結果の出力内容:

```output
ニャー,ニャーと試みにやって見たが誰も来ない.
```
　

---

このセクションでは文字同士もしくは文字列同士の置換について学びました。この他にも正規表現と呼ばれるものを使って「特定のパターンにマッチするものを置換する」といった置換のやり方も存在します（且つ、便利でもあります）。

正規表現に関してはのちほど正規表現の章で詳しく触れていきます。

## 文字列を分割する : split, rsplit, splitlines, partition, rpartitionメソッド

このセクションでは文字列の分割について学んでいきます。split, rsplit, splitlines, partition, rpartitionの5つのメソッドが対象となります。特に一番ベーシックなsplitメソッドは多用します。

文字列の分割結果は文字列を格納したリストとなります。コンマ区切りやスペース区切り、タブ区切りなど特定の文字区切りで各値が意味を持つケースなどで利用します。

※コンマ区切りのデータはCSV（Comma Separated Valuesの略）と呼ばれ、色々な環境やツールで使われていますが、CSVの制御はこのセクションで学ぶメソッドではなく別途CSV用の機能がPythonには用意されていたり、Pandasと呼ばれるライブラリで快適に操作ができるのでそれらを使うことが多めです。CSV関係やPandasなどのライブラリは後々の章で触れます。

---

まずはsplitメソッドから見ていきます。splitは「分割する」といった意味を持つ単語になります。

第一引数に任意の区切り文字を指定すると、その区切り文字で分割された文字列を格納したリストが返ってきます。

以下のサンプルでは半角のコンマで文字列を分割して、1つ1つの文字列を格納したリストにしています。なお、splitメソッドでは結果のリストには分割で指定した文字列（今回のサンプルでは`,`）は結果には含まれません。

```py
str_value = '100,200,300'
print(str_value.split(','))
```

コード実行結果の出力内容:

```output
['100', '200', '300']
```
　

第二引数は分割の上限回数です。例えば2を指定したら2回分割がされ結果のリストの件数が3件になります。回数を超えた部分の文字列は分割されずにそのまま結果のリストの最後の値に残ります。

```py
str_value = '100,200,300,400,500'
print(str_value.split(',', 2))
```

コード実行結果の出力内容:

```output
['100', '200', '300,400,500']
```
　

第二引数を省略した場合には全ての区切り文字で分割が実施されます。

---

rsplitメソッドは他の先頭にrが付くメソッドと同様に、「右側から」分割処理が実行されます。ただし、第二引数を省略した場合には全ての区切り文字で分割が実行されるので、左から分割しても右から分割しても同じ結果になります。つまり、splitメソッドと同じ挙動になります。

splitと同じ結果になるrsplitのコード例 :

```py
str_value = '100,200,300'
print(str_value.rsplit(','))
```

コード実行結果の出力内容:

```output
['100', '200', '300']
```
　

第二引数（最大分割回数）を指定した場合には「右から」分割がされるので、リストの先頭（左端）に未分割の文字列が残ります。

```py
str_value = '100,200,300,400,500'
print(str_value.rsplit(',', 2))
```

コード実行結果の出力内容:

```output
['100,200,300', '400', '500']
```
　

---

splitlinesメソッドは文字列を改行単位で分割します。lineは行という意味も持つ単語となります。

splitメソッドで改行を指定すればいいのでは？という感じもしますが、改行の表現はOSやバージョンなどの環境で変わるうるため、全てを加味するとコードが煩雑になってしまいます。

改行は環境によって文字列中で`\n`で表したり、もしくは`\r\n`と表されたり、`\r`と表されたり、もしくはクォーテーションを三つ使ってそのまま文字列内で改行を入れるということもできます。

試しにWindows上のJupyterで`\n`や`\r\n`という文字を含んだ文字列をprint関数で出力してみると、どちらも改行として表示されます。

```py
print('a\nb')
```

コード実行結果の出力内容:

```output
a
b
```
　

```py
print('a\r\nb')
```

コード実行結果の出力内容:

```output
a
b
```
　

このように改行は複数の表現がありますが、ではsplitメソッドで分割しようとしたらどうなるでしょうか？たとえばsplitメソッドで改行を`\n`区切りで指定していたとして、改行が`\r\n`で表現されているデータが来たときです。

試してみると以下のように、`\r`部分が結果に残ってしまって想定したものになりません。

```py
str_value = '100\r\n200\r\n300'
print(str_value.split('\n'))
```

コード実行結果の出力内容:

```output
['100\r', '200\r', '300']
```
　

プログラムで扱う時にはその辺りの改行表現の差などを気にせずに単純に「改行で分割」としたいところです。そういったケースのために、splitlinesメソッドが用意されておりこちらを使うことで煩雑にコードを書かなくてもシンプルに改行で分割してくれます。

以下のように色々な改行を含んだ文字列に対して実行してみても、同じ結果が得られることが確認できます。

改行が`\n`で表現されているケースでの分割サンプル :

```py
str_value = '100\n200\n300'
print(str_value.splitlines())
```

コード実行結果の出力内容:

```output
['100', '200', '300']
```
　

改行が`\r\n`で表現されているケースでの分割サンプル :

```py
str_value = '100\r\n200\r\n300'
print(str_value.splitlines())
```

コード実行結果の出力内容:

```output
['100', '200', '300']
```
　

改行が`\r`で表現されているケースでの分割サンプル :

```py
str_value = '100\r200\r300'
print(str_value.splitlines())
```

コード実行結果の出力内容:

```output
['100', '200', '300']
```
　

改行が3つの連続したクォーテーションでの文字列表現で直接記述されているケースでの分割サンプル :

```py
str_value = """100
200
300
"""
print(str_value.splitlines())
```

コード実行結果の出力内容:

```output
['100', '200', '300']
```
　

---

partitionメソッドはsplitメソッドと同じように、区切り文字を指定して分割を実行します。ただし以下の点がsplitメソッドと異なります。

- 分割は1回のみ実施されます。
- 分割後の左側の文字列、区切り文字、分割後の右側の文字列の3つの値を格納したタプルが返却されます。
- splitメソッドはリストが返却され、partitionメソッドは分割結果の値が3件になるのを加味してかタプルとなります。返却値の型が異なるので注意してください。
- splitメソッドでは区切り文字は結果のリストには含まれませんが、partitionメソッドでは区切り文字も結果のタプルに含まれます。

実際にコードを書いて試してみます。サンプルとしてコロンを含んだ文字列に対して試してみると、コロンの左右の文字列で結果が分割されていることが確認できます。

```py
str_value = '100:200'
print(str_value.partition(':'))
```

コード実行結果の出力内容:

```output
('100', ':', '200')
```
　

文字列中に複数の区切り文字が含まれていても分割は1回しかされません。タプルの右側の値に区切り文字がそのまま残ります。

```py
str_value = '100:200:300:400'
print(str_value.partition(':'))
```

コード実行結果の出力内容:

```output
('100', ':', '200:300:400')
```
　

文字列中に引数で指定した区切り文字が無い場合には、タプルの最初のインデックスに元の文字列が配置され、2つ目と3つ目のインデックスには空文字が設定されます。区切り文字も含まれない形となります。タプルの値の件数は3件のままです。

```py
str_value = '100:200'
print(str_value.partition(','))
```

コード実行結果の出力内容:

```output
('100:200', '', '')
```
　

---

最後のrpartitionメソッドはメソッド名からも推測できるように、「右から」分割がされます。他の挙動はpartitionと同じです。

```py
str_value = '100:200:300:400:500'
print(str_value.rpartition(':'))
```

コード実行結果の出力内容:

```output
('100:200:300:400', ':', '500')
```
　

## 文字列内に変数などを差し込んだり、特定のフォーマットで値を挿入する : %記号, format, format_mapメソッド, f-strings

変数の値を差し込んだ文字列を作る場合、文字列同士を`+`の記号で連結する方法があります。例えば以下のような書き方をします。

```py
name = 'タマ'
concatenated_str = '飼っている猫の名前は' + name + 'です。'
print(concatenated_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。
```
　

しかし、もし変数の値が文字列以外の値、例えば整数などの場合にはこの方法だとそのままだとエラーになってしまいます。例えば以下のように`age`という整数の変数を連結しようとするとエラーになります。

```py
age = 5
concatenated_str = '飼っている猫の歳は' + age + '歳です。'
```

```output
TypeError: can only concatenate str (not "int") to str
```

concatenateは「連結する」といった意味の単語なので、エラーメッセージは「文字列と（整数ではなく）文字列のみが連結できるよ」といったような内容になります。

整数もしくは別の文字列以外の型の変数を文字列の連結に使いたい場合にはキャストと呼ばれる処理を挟んで対象の変数を文字列にする必要があります（キャストについては後々の章で触れます）。

文字列へのキャストするには対象の変数などを`str()`関数の引数に渡すことで実現できます。先ほどのエラーが出てしまったコードをエラーが出ないように文字列にキャストするように書き直すと以下のようになります。

```py
age = 5
concatenated_str = '飼っている猫の歳は' + str(age) + '歳です。'
print(concatenated_str)
```

コード実行結果の出力内容:

```output
飼っている猫の歳は5歳です。
```
　

この書き方でもやろうとしていた「文字列に変数を差し込んで連結する」という目的は達成できました。ただ、少し記述が煩雑（`+`の記号やキャスト部分など）ですし、文字列の変数想定だった箇所が何かの拍子に別の型の値になってしまって、キャストを忘れていてエラーになってまう・・・みたいなケースも無いわけではありません。

前置きが長くなりましたが、このセクションではそういったケースによりシンプルに・より読みやすい形に文字列へ変数を差し込む方法を学んでいきます。

---

まずは`%`記号を使った書き方から学んでいきます。前の章で触れたように、`%`の記号は整数で使うと余り（剰余）の計算をすることができます。

```py
6 % 4
```

コード実行結果の出力内容:

```output
2
```
　

一方文字列では`%`の記号を使って文字列中に変数を差し込む挙動に使われます。`%`記号と一緒に特定のフォーマットを表す英文字を文字列中で指定して使います。まず最初は「文字列(string)そのままのフォーマット」としての`s`を付与した形の`%s`という表記で文字列でサンプルコードを書いていきます。

文字列と差し込みたい変数の間にはさらに`%`記号で間を分割し、左に文字列右に変数という形で以下のように書きます。

```py
age = 5
concatenated_str = '飼っている猫の歳は%s歳です。' % age
print(concatenated_str)
```

コード実行結果の出力内容:

```output
飼っている猫の歳は5歳です。
```
　

変数を差し込む部分が`%s`のみとなり、複数の`+`記号などが消えてすっきりとした記述となりました。また、対象の変数の文字列へのキャスト（`str()`）も省略する形で書けています。

`%s`の他には`%d`や`%.3f`、`%x`といったような色々な指定があります。ビルトイン関数の章のformat関数でも色々触れましたが、それぞれ以下のような意味と挙動になります（ここで触れる以外にも色々とあります。format関数のセクションで色々説明をしたので、ここでは10進数や16進数などの説明は割愛します）。

- `%s` -> string。文字列としてそのまま扱われます（`str()`関数でキャストした場合と同じような挙動）。文字列への変数の値の挿入などでは一番使う機会が多くなると思います。
- `%d` -> digit。普段の生活で使っている0～9の範囲での10進数での値で文字列内に挿入されます。
- `%.3f` -> float。浮動小数点数で文字列内に挿入されます。3といった部分は任意の数字で、小数点以下第何位まで表示するのかの指定となります。3と指定すれば`0.000`といったような数値で文字列に反映されます。
- `%x` -> hex。16進数で文字列内に挿入されます。

一部、`%s`以外も実際にコードを書いて挙動を確かめてみます。まずは`%d`です。`%d`では10進数の整数として文字列に値が挿入されます。`5.5`といった小数を含んだ値を指定しても整数に変換されるので`5`といった値で文字列で出力されます。

```py
age = 5.5
concatenated_str = '飼っている猫の歳は%d歳です。' % age
print(concatenated_str)
```

コード実行結果の出力内容:

```output
飼っている猫の歳は5歳です。
```
　

`%d`を使った場合には、指定する変数などの値は「整数に変換できる数値」である必要があります。浮動小数点数や整数などは指定できますが、それ以外の例えば文字列などを指定するとエラーになってしまいます（文字列などを挿入する必要があれば`%s`などの方を使います）。

```py
name = 'タマ'
concatenated_str = '飼っている猫の名前は%dです。' % name
```

```output
TypeError: %d format: a number is required, not str
```

エラーメッセージは「`%d`のフォーマットでは文字列ではなく数値が必要だよ」といったようなメッセージになっています。

`%.3f`を使うと、指定する変数の値が小数点以下の特定の桁数の文字列で挿入されます。`5.5`という値の変数で`%.3f`とフォーマットを指定すれば`5.500`という値で文字列に挿入されます。`%.2f`とすれば小数点以下第二位まで表示され、`5.50`といった値で挿入されます。

```py
age = 5.5
concatenated_str = '飼っている猫の歳は%.3f歳です。' % age
print(concatenated_str)
```

コード実行結果の出力内容:

```output
飼っている猫の歳は5.500歳です。
```
　

文字列中に複数の変数を挿入したい場合には、タプルの括弧を使って複数の変数を指定します。例えば`(name, age)`といったようにタプルで書きます。

```py
name = 'タマ'
age = 5
concatenated_str = \
    '飼っている猫の名前は%sです。歳は%s歳です。' % (name, age)
print(concatenated_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

文字列中の`%s`などの指定と、タプル内の値の件数は一致していないとエラーになります（関数の引数で数が合っていない時にエラーになるのと似たような形ですね）。

以下のコードでは文字列中に`%s`の指定が3つある一方で、タプル側の変数が2つしかないためエラーになっています。

```py
name = 'タマ'
age = 5
concatenated_str = \
    '飼っている%sの名前は%sです。歳は%s歳です。' % (name, age)
```

```output
TypeError: not enough arguments for format string
```

エラーメッセージは「文字列の整形（ここでは変数の挿入）に必要な引数（各変数）が足りていないよ」といったメッセージになります。

タプル側の件数が多くてもエラーになります。

```py
name = 'タマ'
age = 5
concatenated_str = \
    '飼っている猫の名前は%sです。歳は3歳です。' % (name, age)
```

```output
TypeError: not all arguments converted during string formatting
```

「文字列の整形（変数の挿入）中に、全ての引数（タプル内の各変数）が（`%s`の数が足りなくて）変換（挿入）できませんでした」といったようなエラーメッセージの内容になります。

また、複数の値の挿入処理にはタプルが使われるため、タプル自体を挿入したい場合にはそのままだとうまくいきません。`%s`などの表記が1つだけで且つ複数の値を格納したタプルの変数を指定した場合には前述の通り件数が一致していないと判断されてエラーになってしまいます。このようなケースではタプルの文字列へのキャストなどの制御が必要になってしまいます。

それ以外にも、関数で引数の数が増えると読みづらくなってくるといったのと同様に、文字列中に`%s`の記述が多くなってくると順番などの制御などでミスをしやすくなってきます。キーワード引数のような機能が欲しくなってきます。

その辺りの`%`による制御の問題点を改善する形で、後述のformatメソッドが`%`による制御よりも後のPythonバージョンで追加されています。

---

`%`記号による制御の次はformatメソッドについて学んでいきます。`%`記号を使った変数などの値の文字列への挿入処理と同様に使えますが、こちらの方がPythonのバージョン的に新しい機能であり、コードの記述量は少し増えますが色々と機能が増えていたり問題点などが改善されていたりします。

使い方としては、まずは文字列中に`{}`の括弧を変数の値を入れたいところに追加します。その後にその文字列でformatメソッドを実行し、引数として挿入したい変数を指定します。シンプルな例だと以下のようなものになります。

```py
name = 'タマ'
formatted_str = '飼っている猫の名前は{}です。'
formatted_str = formatted_str.format(name)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。
```
　

複数の変数を挿入したい場合には`{}`の括弧を複数文字列内に設定します。

```py
name = 'タマ'
age = 5
formatted_str = '飼っている猫の名前は{}です。歳は{}歳です。'
formatted_str = formatted_str.format(name, age)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

複数の引数を指定した際には順番に`{}`部分に値が設定されていきます。例えば`(name, age)`と引数に指定した場合には文字列中の最初の`{}`部分に`name`の引数の値が設定され、次の`{}`部分に`age`の引数の値が反映されます。

この順番を調整したい場合には`{}`の括弧の中に整数の値を設定して`{0}`や`{1}`といったような書き方をします。括弧内の整数は0から始まる引数の番号です（最初の引数が0、その次が1、その次が2...となります）。

以下のように実際にコードを書いてみると、第三引数（`name`）の方が文字列中で第二引数（`age`）の値よりも先に文字列内で設定されることを確認できます。

```py
animal = '猫'
name = 'タマ'
age = 5
formatted_str = '飼っている{0}の名前は{2}です。歳は{1}歳です。'
formatted_str = formatted_str.format(animal, age, name)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

`{}`の括弧で一部はそのままの文字列として使うケースで、且つformatメソッドでの変数の差し込みなどもやりたい場合には`{{}}`と括弧を二重に記述するとその括弧はformatメソッドで無視される普通の括弧の文字列(`{}`)として扱われます（こういった制御をエスケープするなどと言われます）。

以下のサンプルではformatメソッドを使ってもエスケープされた`{}`の括弧の部分が出力に残っていることが確認できます。

```py
name = 'タマ'
age = 5
formatted_str = '飼っている{{猫}}の名前は{}です。歳は{}歳です。'
formatted_str = formatted_str.format(name, age)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている{猫}の名前はタマです。歳は5歳です。
```
　

また、`{name}`や`{age}`といったように括弧の中に引数名を書いておくことで、キーワード引数のように変数の差し込みを指定することもできます。引数の順番のミスなどを避けれますし、引数が多くなっても読みやすいコードにすることができます。

```py
cat_name = 'タマ'
cat_age = 5
formatted_str = '飼っている猫の名前は{name}です。歳は{age}歳です。'
formatted_str = formatted_str.format(
    name=cat_name,
    age=cat_age,
)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

このキーワード引数を使う書き方は仕事でも高い頻度で利用しています。シンプルな変数値の挿入であれば`%`記号を使った処理を使うことも多いですが、変数の数が多くなった場合（3つ以上など）には可読性などの面からformatメソッドでキーワード引数を使って記述することが多めです。引数の数が多くなると読みづらくミスしやすくなってくるので、積極的にキーワード引数などを使っていきましょう。

以下は少し発展的な書き方且つ使う機会は低めとなりますが、`{}`の括弧で指定された値がリストや辞書などの場合、インデックス的に参照することができます。

たとえば`{0}`と書くと第一引数の変数が参照されますが、もしその第一引数の値が`name`というキーを持つ辞書であれば`{0[name]}`と書くことで文字列中に辞書の`name`キーの値を展開することができます。このサンプルでは第一引数（`{0}`）を使っていきますが、第二引数以降でも勿論使用することができます。

```py
dict_value = {
    'name': 'タマ',
    'age': 5,
}
formatted_str = \
    '飼っている猫の名前は{0[name]}です。歳は{0[age]}歳です。'
formatted_str = formatted_str.format(dict_value)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

リストでも同様なことはできます。例えば第一引数にリストの変数を指定して`{0[0]}`と書けば第一引数のインデックス0の値、`{0[1]}`と書けば第一引数のインデックス1の値が展開されます。

```py
list_value = [
    'タマ',
    5,
]
formatted_str = '飼っている猫の名前は{0[0]}です。歳は{0[1]}歳です。'
formatted_str = formatted_str.format(list_value)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

こういった書き方は、多用すると括弧やインデックスの数値などが連続するのでコードが読みづらくなるケースが起こりえます。リストや辞書などを使う場合にも、文字列中はキーワード引数の値単体で設定（例えば`{name}`といった形など）して、引数指定時にインデックスなどを参照することで同じことはできるため、コードが読みづらくなってきたらキーワード引数単体での書き方などがおすすめです。以下書き換え例です。

```py
list_value = [
    'タマ',
    5,
]
formatted_str = '飼っている猫の名前は{name}です。歳は{age}歳です。'
formatted_str = formatted_str.format(
    name=list_value[0],
    age=list_value[1],
)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

第一引数としての`{0}`という表記をサンプルで使ってきましたが、他の書き方、例えばキーワード引数を使ったような書き方も勿論できます。例えば`{name_dict[cat_name]}`みたいな書き方ができます（サンプルでは文字列が長くなってきたので`()`の括弧と改行を使っています）。

```py
name_dict = {'cat_name': 'タマ'}
age_list = [5]

formatted_str = (
    '飼っている猫の名前は{name_dict[cat_name]}です。'
    '歳は{age_list[0]}歳です。'
).format(
    name_dict=name_dict,
    age_list=age_list,
)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

文字列内で辞書に対して特定のキーの値に対してアクセスする方法に関して、注意点としてキーに変数などは使えません。

通常の辞書の値への参照ではキーに変数などが使えます。例えば以下のような辞書の値へのアクセス（`[name_key]`といった書き方）ができます。

```py
dict_value = {'cat_name': 'タマ'}
name_key = 'cat_name'
print(dict_value[name_key])
```

コード実行結果の出力内容:

```output
タマ
```
　

一方で文字列内での辞書の値のキーの参照は`{dict_value['name']}`という書き方ではなく、直接`[name]`といったようにクォーテーション（`'`記号など）無しで記述します。その際には`name`という変数ではなく`name`というキー名でのアクセスとなります。特定のキーに対して変数を使って文字列に値を挿入したい場合には、文字列内でキーへ変数は使えないので、以下のように文字列の外で引数で指定する箇所で（`name=dict_value[name_key]`といった書き方で）設定する必要があります。

```py
name_key = 'name'
age_key = 'age'
dict_value = {
    name_key: 'タマ',
    age_key: 5,
}

formatted_str = '飼っている猫の名前は{name}です。歳は{age}歳です。'
formatted_str = formatted_str.format(
    name=dict_value[name_key],
    age=dict_value[age_key],
)

print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

続いて`{}`の括弧内でコロンを使った書き方について学びます。括弧内で半角のコロンを設定し、コロンの左側に対象の変数（引数順に応じた`{0}`や`{1}`もしくはキーワード引数による`{name}`といったような書き方の部分）を記述し、コロンの右側にフォーマットの文字列（`.3f`など）を指定することで、特定のフォーマットで値を挿入することができます。`{0:.3f}`や`{name:.3f}`といったようにコロンを使って書きます。

`%`記号を使った書き方の際の`%d`とか`%.3f`とかの`%`を除いた部分が該当し、機能もそれらと同じように動作します（例えば`.3f`と指定すれば小数点以下第三位までの文字列の形式で表示されるといった挙動は同じです）。

以下のサンプルでは`age`というキーワード引数を挿入し、小数点以下第三位まで表示する指定で`{age:.3f}`という指定を文字列中でしています。出力結果の文字列が元の値の`5.5`ではなく第三位まで表示する形で`5.500`となっている点が確認できます。

```py
age = 5.5
formatted_str = '猫の年齢は{0:.3f}歳です。'
formatted_str = formatted_str.format(
    age,
)

print(formatted_str)
```

コード実行結果の出力内容:

```output
猫の年齢は5.500歳です。
```
　

---

このセクションの最後のメソッドはformat_mapです。

format_mapメソッドはformatメソッドとほぼ同じような挙動をします。ただし、引数には辞書を1つ指定する形になっています。引数の辞書の各キーと値のセットが、formatメソッドでキーワード引数を使った時のように展開されて文字列中に各値が展開されます。

```py
dict_value = {
    'name': 'タマ',
    'age': 5,
}
formatted_str = '飼っている猫の名前は{name}です。歳は{age}歳です。'
formatted_str = formatted_str.format_map(dict_value)
print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

関数の章でも触れましたが関数（もしくはメソッド）実行時の引数に半角のアスタリスク2個と辞書をセットで引数に指定すると辞書内のキーと値をキーワード引数として展開してくれることを学びました。そちらの書き方とformat関数を組み合わせると、実はformat_mapメソッドを使わなくても同じような挙動を実現できます。例えば以下のようにformatメソッドの引数に`**dict_value`と指定すればformat_mapメソッドを使った時と同じ結果を得ることができます。

```py
dict_value = {
    'name': 'タマ',
    'age': 5,
}
formatted_str = '飼っている猫の名前は{name}です。歳は{age}歳です。'
formatted_str = formatted_str.format(**dict_value)
print(formatted_str)
```

コード実行結果の出力内容:

```output
飼っている猫の名前はタマです。歳は5歳です。
```
　

formatメソッドでもformat_mapメソッドと同じ結果を得られるのに何故format_mapメソッドが用意されているのでしょう？理由としては以下のようなものがあります。ただし、細かい制御とかが必要になった時にformat_mapが必要になる時が稀にある・・・といった程度で、利用頻度的にはformat_mapメソッドは大分少なくなります。

- format_mapメソッドでは引数の辞書のコピーは作成されません。2個のアスタリスクと辞書をformatメソッドに指定した場合は引数に指定した辞書のコピーが作成されます。コピーされる分、メモリや処理時間が僅かに増加します。そのため大きいデータの辞書などを指定する際にはformat_mapの方がパフォーマンス的に有利になります。ただし、大抵はキーワード引数で指定するようなケースでは小さい辞書のケース（数値や文字列が数点など）が多いと思いますので、ほとんどのケースでは差は誤差の範囲です。
- 後々の章で触れますが、クラスを使った継承などの機能を使って辞書の一部の機能を書き換える（上書きする）といったコードを書くことがあります。そのような場合にアスタリスクを2個使った引数指定では「辞書としてコピーされる」ために上書きした部分が無視されてしまうといったケースが発生します。この辺りは後々の章で触れますので、今は「カスタマイズしたものがformatメソッドでは無視されてしまうケースが稀に発生する」程度にお考えください。

---

このセクションの最後に、f-strings（f文字列）にも触れていきます。

f-stringsとは、文字列の引用符（シングルクォーテーションなど）の前にfという文字を付与することで、文字列中に変数などを差し込んだりPythonのコードを実行することができる機能です。

変数部分やPythonのコード部分にはformatメソッドと同じように`{}`の括弧で囲みます。

シンプルなサンプルコードとしては以下のようになります。`猫の...`という文字列部分の先頭にfという文字が付与されていることと、formatなどのメソッド無しに`name`という変数が結果の文字列に含まれているという点に注目してください。

```py
name = 'タマ'
txt = f'猫の名前は{name}です。'
print(txt)
```

コード実行結果の出力内容:

```output
猫の名前はタマです。
```
　

f-stringsを使うと直接変数の挿入などが対応でき、formatメソッドなどの呼び出しも不要なのでコード量が短くて済むというメリットがあります。できることとしては書き方は結構異なるものの、formatメソッドに近い内容となっています。

f-stringsでの`{}`の括弧内ではPythonでの処理などを書くこともできます。例えば以下のように文字列内で足し算をしたりすることもできます。

```py
age = 5
print(f'来年は{age + 1}歳になります。')
```

コード実行結果の出力内容:

```output
来年は6歳になります。
```
　

関数の実行なども文字列中で行うことができます。

```py
def get_name():
    return 'タマ'


print(f'猫の名前は{get_name()}です。')
```

コード実行結果の出力内容:

```output
猫の名前はタマです。
```
　

`%`記号を使った書き方やformatメソッドで、フォーマット（例えば小数点以下第何位までの文字列にするのかなど）を指定するにはformatメソッドと同じように半角のコロンの記号（`:`）を挟み、右側にフォーマットを指定します。

```py
value = 123.456789
print(f'小数点以下第三位までを含んだ値は{value:.3f}です。')
```

コード実行結果の出力内容:

```output
小数点以下第三位までを含んだ値は123.457です。
```
　

なお、このフォーマット指定部分（コード上では`.3f`となっている部分）は書式指定子（format specifier）などと呼ばれます。Python内部のコードを読むと、引数名などがformat_specなどになっていますがこの引数名はformat specifierに由来します。

f-strings中では、このフォーマット指定子部分でさらに`{}`の括弧を入れる（入れ子にすると言います）と、フォーマット指定子部分にも変数を指定することができます（条件に応じてフォーマット指定子を変更したりすることができます）。

```py
format_spec = '.2f'
value = 123.456789
print(f'小数点以下第二位までを含んだ値は{value:{format_spec}}です。')
```

コード実行結果の出力内容:

```output
小数点以下第二位までを含んだ値は123.46です。
```
　

## 任意の文字列でリストの値を1つの文字列に連結する : joinメソッド

joinメソッドは任意の文字列を格納したリストなどの値を、指定の文字列を間に挟んだ形で連結をします。

間に挟む文字列は変数も使えますが、直接固定の文字や文字列が指定されることが多めです。例えばコンマ区切りでリストの値を連結したい時には`','.join`といった形の書き方がされます。メソッドの第一引数に連結したいリスト（もしくはタプルなどの値）を指定します。

コンマ区切りでリスト（`animals`という変数）を連結するサンプル :

```py
animals = ['猫', '犬', '兎']
print(','.join(animals))
```

コード実行結果の出力内容:

```output
猫,犬,兎
```
　

アンダースコア二個（`__`）でリストを連結するサンプル :

```py
animals = ['猫', '犬', '兎']
print('__'.join(animals))
```

コード実行結果の出力内容:

```output
猫__犬__兎
```
　

リストの中身が文字列以外（数値など）になっている場合にはエラーになります。

```py
int_list = [1, 2, 3]
print(','.join(int_list))
```

```
TypeError: sequence item 0: expected str instance, int found
```

リストやタプルのような順番を持った各値を格納したものは総括してシークエンス（sequence）とも呼ばれます。
そのためエラーメッセージは「シークエンス（リスト）のインデックス0の要素（item）で、文字列（str）のインスタンス想定のところに整数（int）の値がありました」といったよう内容になります。

## 文字列中に出現する特定の文字列の回数を取得する : countメソッド

countメソッドは第一引数に指定した文字列が、対象の文字列中にいくつ含まれているかの件数を返します。

文字列中に「猫」という文字が4つあるため4が返却されているサンプル :

```py
txt = (
    '吾輩は猫である。'
    'その後猫にもだいぶ逢ったがこんな片輪には一度も出会わした事がない。'
    '猫が来た猫が来たといって夜中でも何でも大きな声で泣き出すのである。'
)
print(txt.count('猫'))
```

コード実行結果の出力内容:

```output
4
```
　

第二引数は検索範囲の開始インデックス、第三引数は検索範囲の終了インデックスから1マイナスした値となります。

0～11までのインデックスの文字列範囲を検索対象とするサンプル :

```py
txt = (
    '吾輩は猫である。'
    'その後猫にもだいぶ逢ったがこんな片輪には一度も出会わした事がない。'
    '猫が来た猫が来たといって夜中でも何でも大きな声で泣き出すのである。'
)
print(txt.count('猫', 0, 12))
```

コード実行結果の出力内容:

```output
2
```
　

それぞれスライスで使われるコロンの右側の整数と右側の整数の値に該当します。つまり、検索対象の範囲を確認するには以下のような文字列へのスライスをすることで対応ができます（前述のコードサンプルの第二引数の0と第三引数の12をスライスで指定しています）。

```py
print(txt[0:12])
```

コード実行結果の出力内容:

```output
吾輩は猫である。その後猫
```
　


## 文字列の端から空白文字などの特定の文字を取り除く : strip, lstrip, rstripメソッド

stripメソッドでは文字列の先頭と末尾の特定の文字を削除します。stripは「取り除く」といった意味の単語になります。

replaceメソッドで空文字を指定（空文字で置換）しても、特定の文字列を削除することができますが、replaceメソッドと比べてstripメソッドは以下の違いがあります。

- 引数は省略することができます。
- 引数を省略した場合は、文字列両端のスペースや改行などの空白文字と呼ばれる文字が削除されます。
- 文字列ではなく文字単位で削除が実行されます。例えば引数に`猫犬`という文字列を指定した場合、`猫犬`という文字列で削除がされるのではなく、`猫`と`犬`という文字単位で削除がされます。

まずは引数を省略したケースでの挙動を確認してみます。以下のような文字列の両端にスペースや改行などの空白文字（`\n`は改行1つ分を表す文字になります）を含んだ文字列で進めます。

```py
txt = '　　　　吾輩は猫である。\n\n'
print(txt)
```

コード実行結果の出力内容:

```output
　　　吾輩は猫である。


```
　

stripメソッドを通してみると、両端にあった空白文字が取り除かれていることが確認できます。

```py
txt = '　　　　吾輩は猫である。\n\n'
print(txt.strip())
```

コード実行結果の出力内容:

```output
吾輩は猫である。
```
　

第一引数に文字列を指定した場合には、その文字列で1文字ずつ両端で削除処理が実行されます。例えば引数に`猫犬`という文字列を指定すれば、両端から`猫`もしくは`犬`という文字ではなくなるまで削除処理が実行されます。

```py
txt = '猫犬猫兎狼犬猫犬'
print(txt.strip('猫犬'))
```

コード実行結果の出力内容:

```output
兎狼
```
　

---

lstripメソッドは、stripメソッドの左端のみ文字の削除処理が実行されるメソッドです。lはleftのlとなります。

使い方や引数などはstripメソッドと同じです。以下のコードでは右端の`猫`と`犬`という文字が残っていることが確認できます。

```py
txt = '猫犬猫兎狼犬猫犬'
print(txt.lstrip('猫犬'))
```

コード実行結果の出力内容:

```output
兎狼犬猫犬
```
　

---

rstripメソッドはlstripメソッドなどの流れから分かる通り、右端のみ文字の削除を行います。メソッド名の先頭のrはrightのrとなります。使い方はstripやlstripメソッドと同じです。

```py
txt = '猫犬猫兎狼犬猫犬'
print(txt.rstrip('猫犬'))
```

コード実行結果の出力内容:

```output
猫犬猫兎狼
```
　

## 文字列を全て大文字にする : upperメソッド

upperメソッドは文字列を全て大文字に変換します。アルファベットの文字列部分が変換対象となります。

upper caseで「大文字」という意味なので、メソッド名はそちらに由来します。

```py
txt = 'Apple and orange'
print(txt.upper())
```

コード実行結果の出力内容:

```output
APPLE AND ORANGE
```
　

半角文字だけでなく全角文字でも同様に変換することができます。

```py
txt = 'Ａｐｐｌｅ'
print(txt.upper())
```

コード実行結果の出力内容:

```output
ＡＰＰＬＥ
```
　

## 文字列を全て小文字にする : lowerメソッド

lowerメソッドはupperメソッドとは逆に、アルファベットの大文字の文字列部分を小文字に変換します。lower caseで「小文字」という意味なので、メソッド名はそちらに由来します。

大文字と小文字の変換が逆なだけで、使い方や挙動はupperメソッドと同じです。

```py
txt = 'Apple And Orange'
print(txt.lower())
```

コード実行結果の出力内容:

```output
apple and orange
```
　

## 数字の文字列をゼロ埋めする : zfillメソッド

任意の整数を、特定の文字数になるまで左側に0を追加する処理をゼロ埋めもしくはゼロパディング（zero padding）と言います。

例えば`135`という文字を5文字に揃えるゼロ埋めをすると、`00135`となります。

zfillメソッドは、このゼロ（zero）埋め（fill）の処理をしてくれます。第一引数には結果の文字数を整数で指定します。5を指定したら5文字になるまで0が付与され、7を指定したら7文字になるまで0が付与されます。

```py
txt = '135'
print(txt.zfill(5))
```

コード実行結果の出力内容:

```output
00135
```
　

## 文字列を特定の文字数になるまで文字を追加する : rjust,  ljust, centerメソッド

rjust、ljust、centerメソッドもzfillと同じように任意の文字数になるまで文字を埋める挙動をします。ただし、zfillと以下の挙動が異なります。

- 埋める文字は0ではなく任意の文字を指定することができます。
- メソッドによって、埋める文字の位置を左端、右端、もしくは両端を選択できます。

---

rjustメソッドは文字列は右に配置され、左端に任意の文字が埋められます。right justifyingで「右ぞろえ」という意味であり、メソッド名はそちらに由来します。

第一引数に最終的な文字数の整数、第二引数に埋める文字を指定します。

```py
txt = '犬犬'
print(txt.rjust(5, '猫'))
```

コード実行結果の出力内容:

```output
猫猫猫犬犬
```
　

---

ljustメソッドは元の文字列は左ぞろえに配置され、右側に不足している数だけ文字が埋められます。

```py
txt = '犬犬'
print(txt.ljust(5, '猫'))
```

コード実行結果の出力内容:

```output
犬犬猫猫猫
```
　

---

centerメソッドは元の文字列は中央ぞろえに配置され、左端と右端両方に腹側している数がけ文字が埋められます。

```py
txt = '犬'
print(txt.center(5, '猫'))
```

コード実行結果の出力内容:

```output
猫猫犬猫猫
```
　

左右に埋める文字の数が奇数の場合は、左端の方が多く埋められます。

```py
txt = '犬'
print(txt.center(5, '猫'))
```

コード実行結果の出力内容:

```output
猫猫犬猫猫
```
　


## 先頭の1文字を大文字にして他を小文字にする : capitalizeメソッド

重要度 : ★★☆☆☆（最初は知らなくてもいいかも）

※以降の文字列操作のセクションは、比較的マイナーなものが多くなります。一応一通り触れていきますが、スキップいただいても大きな問題はありません。

---

capitalizeメソッドはアルファベットで先頭の一文字を大文字に変換し、その他を小文字に変換します。英語の文章などで便利です。

capitalizeという単語自体は「資本化する」といったようなお金関係の意味の他にも「大文字で始める」といった意味もあり、メソッド名はそちらに由来します。

```py
txt = 'apple and orange'
print(txt.capitalize())
```

コード実行結果の出力内容:

```output
Apple and orange
```
　

小文字だけが変換されるというわけではなく、文字列中に大文字が含まれている場合には先頭の1文字以外は大文字から小文字へと変換されます。

```py
txt = 'APPLE AND ORANGE'
print(txt.capitalize())
```

コード実行結果の出力内容:

```output
Apple and orange
```
　

## 各英単語の最初の1文字を全て大文字にする : titleメソッド

titleメソッドはアルファベットの各単語の先頭の一文字を大文字にし、他を小文字に変換します。

英文ではタイトルや見出しなどでは「主な単語の先頭の1文字を大文字にし、残りを小文字表記にする」という書き方がされることが多くあり、このような書き方をタイトルケース（title case）と呼びます。titleメソッドの名前の由来はタイトルケースに由来します。

注意点として、通常は`and`や`the`などの単語は小文字のままで、名詞などの単語は先頭を大文字にする形（例えば`Apple and Orange`といったような形）でタイトルケースが反映されますが、Pythonのtitleメソッドは全ての単語で最初の1文字が大文字になります。

```py
txt = 'apple and orange'
print(txt.title())
```

コード実行結果の出力内容:

```output
Apple And Orange
```
　

## 大文字と小文字を入れ替える : swapcaseメソッド

swapcaseメソッドは小文字部分を大文字にし、大文字部分を小文字にします。swapは「交換する」といった意味を持ちます。

```py
txt = 'Apple And Orange'
print(txt.swapcase())
```

コード実行結果の出力内容:

```output
aPPLE aND oRANGE
```
　

## 全ての文字列が大文字かどうか調べる : isupperメソッド

isupperメソッドは文字列内のアルファベットが全て大文字の場合に真偽値のTrueを返し、それ以外の場合にはFalseを返却します。他のセクションで触れた通り、`upper case`で大文字という意味なので、「文字列 is upper case」といった意味合いで真偽値を返す形でメソッド名がisupperとなっています。

```py
txt = 'APPLE AND ORANGE'
print(txt.isupper())
```

コード実行結果の出力内容:

```output
True
```
　

文字列中に小文字が含まれているとTrueではなくFalseが返却されます。

```py
txt = 'Apple And Orange'
print(txt.isupper())
```

コード実行結果の出力内容:

```output
False
```
　

## 全ての文字列が小文字かどうか調べる : islowerメソッド

islowerメソッドはisupperメソッドとは逆で、文字列のアルファベットが全て小文字の場合に真偽値のTrueを返します。`lower case`で小文字という意味になります。

```py
txt = 'apple and orange'
print(txt.islower())
```

コード実行結果の出力内容:

```output
True
```
　

1文字でも大文字が含まれていればFalseとなります。

```py
txt = 'Apple and Orange'
print(txt.islower())
```

コード実行結果の出力内容:

```output
False
```
　

なお、isupperメソッドも同様ですが大文字のアルファベット以外の記号や日本語などが含まれていてもそれらは判定に影響しません。あくまで小文字が含まれている文字列であり且つ大文字が含まれていないという条件になります。

```py
txt = 'apple リンゴ'
print(txt.islower())
```

コード実行結果の出力内容:

```output
True
```
　

## 各単語の最初の1文字が全て大文字・他が小文字になっているかを調べる : istitleメソッド

istitleメソッドは少し前のtitleメソッドのセクションで触れた（厳密ではありませんが）タイトルケース（各単語の先頭の1文字が大文字）かどうかの真偽値を返します。

```py
txt = 'Apple And Orange'
print(txt.istitle())
```

コード実行結果の出力内容:

```output
True
```
　

いずれかの単語で先頭が大文字になっていない単語があると結果はFalseになります。

```py
txt = 'Apple and orange'
print(txt.istitle())
```

コード実行結果の出力内容:

```output
False
```
　

## 文字列が全て英数字などになっているかどうかを調べる : isdecimal, isdigit, isnumeric, isasciiメソッド

このセクションでは文字列の内容が特定の文字列かどうか（10進数の整数のみの文字列かどうか、アルファベットのみの文字列かどうかなど）の判定用の真偽値を取得する各メソッドについて学んでいきます。

---

isdecimalメソッドは文字列が10進数（普段の生活で使っている、0～9までの10個の数字での数値表現）で表すことができる整数の文字列かどうかの真偽値を返却します（`decimal number`で10進数という意味になります）。整数以外の小数（もしくは小数記号）などが含まれている場合にはFalseとなります。記号や日本語・英語などの整数以外が含まれていてもFalseとなります。

たとえば150といった数値の文字列はTrueとなります。

```py
txt = '150'
print(txt.isdecimal())
```

コード実行結果の出力内容:

```output
True
```
　

全角であっても内容が整数のみであれば結果はTrueとなります。

```py
txt = '１５０'
print(txt.isdecimal())
```

コード実行結果の出力内容:

```output
True
```
　

整数以外の値、例えば小数点などが含まれているとFalseとなります。

```py
txt = '3.14'
print(txt.isdecimal())
```

コード実行結果の出力内容:

```output
False
```
　

記号や空白文字なども含まれているとFalseとなります。例えば以下のように左端にスペースなどが含まれていてもFalseとなってしまいます。もしそういった空白文字が入る可能性があるプログラムの場合には前のセクションで触れたstripメソッドなどを使って余分な空白文字の削除を行って処理すると判定で想定外の結果になったりすることを避けられます。

```py
txt = '  150'
print(txt.isdecimal())
```

コード実行結果の出力内容:

```output
False
```
　

---

isdigitメソッドはisdecimalと近い挙動をするメソッドで、整数かどうかの真偽値を返します。ただしこちらは通常の`0～9`の数字だけでなく、数値の周りを〇で囲っている`①`や`②`といった丸付き数字の文字や指数の文字（2の3乗の3部分など、上付きの小さい数字の文字）などの特殊な数字の文字が一部許容します（isdecimalメソッドよりもTrueになる条件が多くなります）。

isdecimalが名前の通り10進数かどうかの判定の一方で、digitは「アラビア数字（123などの文字）」といった意味を持つので、isdigitは特殊な文字も含めてアラビア数字かどうかといった判定になります。

isdecimalと同様に通常の整数でTrueになるサンプル :

```py
txt = '150'
print(txt.isdigit())
```

コード実行結果の出力内容:

```output
True
```
　

isdecimalと同様に整数以外の文字が含まれているためFalseになるサンプル :

```py
txt = '150円'
print(txt.isdigit())
```

コード実行結果の出力内容:

```output
False
```
　

特殊な`①`などの丸付き文字でもTrueになることを確認するサンプル :

```py
txt = '①②'
print(txt.isdigit())
```

コード実行結果の出力内容:

```output
True
```
　

特殊な`²`などの指数部分の文字でもTrueになることを確認するサンプル（変換などはやりづらい文字なので、コード実行の際にはコードサンプルのコピーなどをお願いします） :

```py
txt = '²³⁴'
print(txt.isdigit())
```

コード実行結果の出力内容:

```output
True
```
　

---

isnumericメソッドではさらに、isdigitメソッドの「アラビア数字の文字」という制限が無くなります（isdigitよりも多くの文字が対象になります）。文字列が全て数字を表す文字であればTrueになります。

アラビア数字という制約が無くなるので、例えば`Ⅲ`といったローマ数字でもTrueが返ります。

```py
txt = 'ⅠⅢⅥ'
print(txt.isnumeric())
```

コード実行結果の出力内容:

```output
True
```
　

他にも漢字の文字列でもTrueになってくれます。

```py
txt = '七五三'
print(txt.isnumeric())
```

コード実行結果の出力内容:

```output
True
```
　

---

isasciiメソッドはASCIIコードと呼ばれる文字、例えば半角の英数時や一部の記号(`@`の記号など)、改行などの特殊文字のみで文字列が構成されている場合にTrueを返却します。

```py
txt = '~@abcABC123'
print(txt.isascii())
```

コード実行結果の出力内容:

```output
True
```
　

全角文字などではFalseが返却されます。

```py
txt = 'ＡＢＣ'
print(txt.isascii())
```

コード実行結果の出力内容:

```output
False
```
　

---

他にもisalphaやisalnumなどのメソッドも存在しますが、こちらは利用頻度が少ない印象なのと、名前的にアルファベット（英字）かどうか（isalpha）、英数字かどうか（isalnum）に思えますが、漢字などの全角文字も対象となる少し直観に反したものになっているためここでは説明を割愛します。

## 文字列が全て空白文字かどうか調べる : isspace

isspaceメソッドは、文字列が全て空白文字になっているかどうかの真偽値を返却します。空白文字は半角スペースや全角スペース・改行（文字列中では`\n`と表記されることも多くあります）・タブ（こちらも文字列中では`\t`と表記されることも多めです）などが該当します。

```py
txt = ' 　\n\t'
print(txt.isspace())
```

コード実行結果の出力内容:

```output
True
```
　

スペースなどが含まれていても、空白文字以外が文字列中に存在するとFalseになります。

```py
txt = '猫犬 　\n\t'
print(txt.isspace())
```

コード実行結果の出力内容:

```output
False
```
　

## 文字コードの変換を行う : encode. decodeメソッド

encodeメソッドとdecodeメソッドは文字列の文字コードを変換します。基本的にPythonでテキストを扱う場合にはUTF-8と呼ばれる文字コードがほぼほぼですが、古いファイルや環境、ファイルフォーマットなどによっては他の文字コード（Shift_JISなど）を扱わないといけないケースがたまに発生します。

ただし、文字列のencodeやdecodeメソッドを利用するというよりかは、テキストファイルなどの読み書き時にこれらの文字コードを指定するケースが多めです。

文字列自体のメソッドはあまり使うケースが少ないとは思いますので、ここでは軽く触れる程度に抑えておきます（ファイル操作などは後々の章でしっかりと学びます）。

まずはencodeメソッドからです。encodeメソッドではPython上の通常の文字列から、特定の文字コードの値に変換します。変換後の値はbytesクラスのインスタンスとなり、たとえばShift_JISに変換すると`\x94L`といった値になり、ぱっと見では読めない値になってしまいます。

encodeメソッドの第一引数には文字コードを指定します。今回はShift_JISに変換しようと思いますので、`sjis`という値を指定します（他にも`utf-8`などの決まった値が色々あります）。

```py
txt = '猫犬'
sjis_txt = txt.encode('sjis')
print('テキストの内容:', sjis_txt, '\n型:', type(sjis_txt))
```

コード実行結果の出力内容:

```output
テキストの内容: b'\x94L\x8c\xa2' 
型: <class 'bytes'>
```
　

decodeメソッドはencodeメソッドと逆の動作をします。つまりShift_JISなどの文字コードに変換された値を、再びPython上で使える普通の文字列（`猫犬`といったように、人が普通に読める文字列）に戻します。第一引数には対象の値が何の文字コードなのかを指定します。

```py
txt = sjis_txt.decode('sjis')
print(txt)
```

コード実行結果の出力内容:

```output
猫犬
```

# 参考文献・サイトまとめ

- [「関数」と「メソッド」の違い](https://wa3.i-3-i.info/diff97function.html)
- [Pythonで文字列・数値を右寄せ、中央寄せ、左寄せ](https://note.nkmk.me/python-rjust-center-ljust/)
- [Pythonで大文字・小文字を操作する文字列メソッド一覧](https://note.nkmk.me/python-capitalize-lower-upper-title/)
- [Python, formatで書式変換（0埋め、指数表記、16進数など）](https://note.nkmk.me/python-format-zero-hex/)
- [Pythonで文字列が数字か英字か英数字か判定・確認](https://note.nkmk.me/python-str-num-determine/)
- [Python strip・lstrip・rstrip 空白を削除する](https://pg-chain.com/python-strip-lstrip-rstrip)
- [Pythonで文字列を置換（replace, translate, re.sub, re.subn）](https://note.nkmk.me/python-str-replace-translate-re-sub/)
- [Pythonで文字列・数値をゼロ埋め（ゼロパディング）](https://note.nkmk.me/python-zero-padding/)
- [Python 文字を検索し値を返す(find/index)](https://itsakura.com/python-find-index)
- [文字の変換にはstr.translate()が便利](https://qiita.com/tag1216/items/df6c93bdb823dd48af6c)
- [Comma-Separated Values](https://ja.wikipedia.org/wiki/Comma-Separated_Values)
- [Pythonで文字列を分割（区切り文字、改行、正規表現、文字数）](https://note.nkmk.me/python-split-rsplit-splitlines-re/)
- [改行の、\nと\r\nの違いは何ですか？](https://ja.stackoverflow.com/questions/12897/%E6%94%B9%E8%A1%8C%E3%81%AE-n%E3%81%A8-r-n%E3%81%AE%E9%81%95%E3%81%84%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B)
- [Python String partition()](https://www.programiz.com/python-programming/methods/string/partition)
- [プログラマが持つべき心構え (The Zen of Python)](https://qiita.com/IshitaTakeshi/items/e4145921c8dbf7ba57ef)
- [PEP 3101 -- Advanced String Formatting](https://www.python.org/dev/peps/pep-3101/)
- [what is the meaning of colon in python's string format?](https://stackoverflow.com/questions/43848164/what-is-the-meaning-of-colon-in-pythons-string-format)
- [What is difference between str.format_map(mapping) and str.format](https://stackoverflow.com/questions/36780729/what-is-difference-between-str-format-mapmapping-and-str-format)
- [PEP 498 -- Literal String Interpolation](https://www.python.org/dev/peps/pep-0498/)
- [string --- 一般的な文字列操作](https://docs.python.org/ja/3/library/string.html)
- [Definition and Examples of Title Case and Headline Style](https://www.thoughtco.com/title-case-capitalization-1692469)
- [文字列の中の文字が数を表す文字かどうかを判定する(isdecimal, isdigit, isnumeric)](https://www.javadrive.jp/python/string/index14.html)
- [[Python] 文字列が数字であることを判別する（isdigit, isdecimal, isnumeric）](https://hibiki-press.tech/python/isdigit/899)
- [文字列の中の文字が英字を表す文字かどうかを判定する(isascii, isalpha, isalnum)](https://www.javadrive.jp/python/string/index15.html)