Python Tech

Pythonで文字数制限 日本語文字列のカウントと切り詰め方法まとめ

2021年5月28日

文字列の処理は特に重要なテクニックですが、言語によって少しずつ仕様が異なります。

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のlen()では全角・半角を区別せずに1文字として文字数をカウントします。一方、全角・半角を区別して文字数を数えるにはunicodedata.east_asian_widthを活用します。

日本語の2バイト文字を2文字として文字数制限をするには上記テクニックを使うといいでしょう。

  • この記事を書いた人

次世代ペンギン

長いのでペンギンとお呼びください。システム開発・プログラミングのお仕事をしています。甘味とコーヒーは生命線。日常での学びを記事にしています。

人気の記事

1

キャリアアップのため、または高収入を目指して、しっかりプログラミングを学びたいという人が増えてきましたね。 この記事では現役のエンジニアである私が、実際に仕事で稼げるようになるためのスクール選びで失敗 ...

2

先日の記事では、初心者からフリーランスプログラマーになる難しさと、それでもなんとか稼げるようになるにはどうしたらいいか解説しました。 今回の記事では、稼げるフリーランサーになるために必要な要素を、もう ...

3

気休めだけの甘い言葉は書きません。 最近は多くの企業やサイトで、使い捨てられるプログラマーが欲しいがために、甘い言葉で初心者プログラマを誘い出しています。 この記事では、まずは「現実」をちゃんと理解し ...

4

Vuetifyの v-progress-circular コンポーネントは、数値データや処理状況を環状(円状)のデザインで教えてくれるUIデザインです。 ローディングのスピナー(処理中のマーク)として ...

5

※画像はずとまよの新曲とは一切関係ありません   ずっと真夜中でいいのに。(以下、ずとまよ)の新曲『勘ぐれい』のMVが12月1日に公開されましたね。 MV前に公開されていた原曲を聴き、神曲な ...

6

Vuexのstore(ストア)を使うと、各コンポーネント間で個別にデータのやり取りすることなく、データを一元的に管理できます。Vueでは欠かせない機能といえるでしょう。 state(変数、コンポーネン ...

-Python, Tech

© 2021 ペンギンのーと