文字列の処理は特に重要なテクニックですが、言語によって少しずつ仕様が異なります。
Pythonでも、特に日本語などの全角文字を扱う際に、文字列の処理で覚えておいたほうがいいポイントがあります。
今回の記事ではPythonで日本語文字列の
- 長さを取得する(カウント)方法
- 文字数制限する(スライス、部分文字列を抽出)方法
をまとめています。日常的に使える知識を再確認しておきましょう。
文字列の長さを取得
全角・半角を区別しない(len)
文字列の長さを数えるなら、len
関数を使います。
Pythonのlen()は、全角2バイト文字)・半角(1バイト文字)を区別せず、すべて1文字としてカウントします。
# カウント(1バイト文字・2バイト文字を区別しない)
print(len('abcあいう')) # 6
特殊文字も1文字としてカウントされます。
# 特殊文字
print(len('\n')) # 1
print(len('\r\n')) # 2
print(len('\t')) # 1
print(len('あい\tうえお')) # 6
例として使っている各文字の意味は以下の通り。
- \n 改行コード(LF)改行を表す
- \r 改行コード(CR)Windowsなどで改行コードに使われる
- \t タブを表す
※バックスラッシュはスラッシュの逆の形であり、違うものなので注意(MacではOptionを押下しながら¥キー)
全角・半角を区別する
Pythonの標準関数len()
では、全角と半角を区別しないのでした。
全角文字(2バイト)と半角文字(1バイト)を区別するには、unicodedata モジュールを用いて各文字の幅をチェックします。
unicodedataモジュールは、その名の通りユニコード(Unicode)に関するデータセットを持つ。
unicodedata.east_asian_width(chr=[文字])
は、渡した文字のeast asian width(東アジアの文字幅)を返す。
返ってくるのは'Na'や'A'といった文字列の形であり、これを元に文字が全角(2バイト)なのか半角(1バイト)なのか判断する。
unicodedata Docs
サンプルとしていくつかの文字を渡したときにどんな値が返ってくるか確認しましょう。
print(unicodedata.east_asian_width('A'))
# Na
print(unicodedata.east_asian_width('あ')) # 全角ひらがな
# W
print(unicodedata.east_asian_width('ア')) # 半角カタカナ
# H
このunicodedata.east_asian_width
を使って、全角・半角を区別しながら文字列の長さを返す関数を作ると以下のようになります。
import unicodedata
def length_double_byte_str(text):
""" 全角・半角を区別して文字列の長さを返す
"""
count = 0
for c in text:
# 全角文字などの2バイト文字は'F','W','A'のいずれかに当てはまるとする
if unicodedata.east_asian_width(c) in 'FWA':
count += 2
else:
count += 1
return count
呼び出し側
len_str = length_double_byte_str('abcあいう')
print(len_str) # 9
このサンプルでは
‘abc’は半角文字なので合計3、
‘あいう’は全角文字なので合計6としてカウントされています。
文字数を制限する(切り詰める)
全角・半角を区別しない
文字列の一部を抽出するのに、最もシンプルなやり方はスライスをつくることです。
text_after = text[start:end]
text:文字列の全体
start: 開始位置
end: 終了位置の一つ後
text_after: スライスされた文字列
text = '012345'
s_text = text[1:5]
print(s_text)
# 1234
文字数を制限(先頭から一定の文字数を数え、それを超えたらカットする)する場合は、単に開始位置を 0
とすればOKです。
text_after = text[0:制限文字数-1]
なお、len()
と同じように、Pythonはスライスでも全角(2バイト文字)・半角(1バイト文字)を区別せず、どちらも1文字として扱います。
# 一般的な文字列スライス(1バイト文字・2バイト文字を区別しない)
text = 'abcdef'
s_text = text[0:4] # 添字4の一つ前まで(3)の文字列をスライスで取得
print(s_text)
# abcd
# 半角英数字なら大文字でももちろん同じ結果に
text = 'ABCDEF'
s_text = text[0:4]
print(s_text)
# ABCD
# スライスは2バイト文字も1文字とカウントされる
text = 'あいうえおかき'
s_text = text[0:4]
print(s_text)
# あいうえ
# 特殊文字も1文字としてカウントされる
text = 'あいう\nえお'
s_text = text[0:5]
print(s_text)
# あいう
# え
全角・半角を区別する
Pythonのスライスは全角・半角文字を区別しません。
全角、半角を区別しながら、文字列を切り抜くには unicodedata.east_asian_width
を活用します。
unicodedata.east_asian_width
は渡した文字の幅を返すので、これで1文字ずつチェックし、所望の長さの文字列を取得します。
以下は全角・半角を区別して文字数制限(切り詰め)をするサンプルです。
def truncate_double_byte_str(text, len):
""" 全角・半角を区別して文字列を切り詰める
"""
count = 0
sliced_text = ''
for c in text:
if unicodedata.east_asian_width(c) in 'FWA':
count += 2
else:
count += 1
# lenと同じ長さになったときに抽出完了
if count > len:
break
sliced_text += c
return sliced_text
呼び出し側
# 1バイト文字は1文字、2バイト文字は2文字としてスライスする場合
text = 'abcあいう'
s_text = truncate_double_byte_str(text, len=5)
print(s_text)
# abcあ
text = 'abcあいう'
s_text = truncate_double_byte_str(text, len=6)
print(s_text)
# abcあ
上記サンプルでは、半角を1、全角を2とカウントします。
そのため、len=5
でもlen=6
でも同じ結果となります。
Pythonの学習法について
Python の勉強が辛くなっていませんか?
Pythonは比較的取り組みやすい言語と言われていますが、プログラミング初心者にとっては分からないことだらけ。
ゼロから独学で勉強するのは厳しい道のりです。
今回、様々な現場、システム、言語を経験してきた現役エンジニアの立場から、初心者でも挫折しない学習方法を解説する記事を書きました。もちろん、お金をかけずに習得できる方法も解説しています。
できるだけストレスがかからない勉強法を解説しているので、ぜひ参考にしてみてくださいね。
まとめ
Pythonのlen()では全角・半角を区別せずに1文字として文字数をカウントします。一方、全角・半角を区別して文字数を数えるにはunicodedata.east_asian_width
を活用します。
日本語の2バイト文字を2文字として文字数制限をするには上記テクニックを使うといいでしょう。