記録は美しく (Python入門講座第4回)¶

print()関数は与えられた引数のデータ型に応じて文字に変換してくれます。 しかし、数値を精度に応じた桁数で表示するなどデータを文字として出力する方法を 制御する必要にすぐに直面するでしょう。

ということで、今回は文字列(およびそれに関係したデータ型)の取り扱いについて学びます。

目標は、

__________________________________フィボナッチ数の数表_________________________________
         00,     01,     02,     03,     04,     05,     06,     07,     08,     09
00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55
10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765
20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040

という形で数表を印刷することです。

きょうの目標¶

今日の講座では、数表の印刷 を例に


  • 文字型(str)データのメソッド : .join(), .split() など

  • Unicode文字列(str)とバイト列(bytes) : u"abc" とb"abc"

  • 文字列の整形(Format)

    str型の.format()メソッド

    フォーマット済み文字列定数: f""


などについて学びます。

 数表の印刷¶

n=0..29のフィボナッチ数列fib(n)の値を次のような形で印刷するPythonプログラムを作って見ましょう。

__________________________________フィボナッチ数の数表_________________________________
         00,     01,     02,     03,     04,     05,     06,     07,     08,     09
00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55
10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765
20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040
In [1]:
#プログラムと実行結果
def fib(n:int)->int:
    if n == 0 or n == 1:
        value= 1
    else:
        value= fib(n-1) + fib(n-2)
    return value

def 数表の印刷():
    print ("フィボナッチ数の数表".center(77,"_"))
    print ( "   {0}".format(
        ",".join(("     {0:02d}".format(c) for c in range(10))))
      )
    for r in range(0,30,10):
        print("{0:02d}:{1}".format(
            r,
            ",".join(("{0:7d}".format(fib(c)) for c in range(r,r+10)))
        ))
        
if __name__ == "__main__": 数表の印刷()
__________________________________フィボナッチ数の数表_________________________________
        00,     01,     02,     03,     04,     05,     06,     07,     08,     09
00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55
10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765
20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040

Notes:¶

fib()は前回と同じ定義を使います。

数表を印刷する関数はたとえば、このようになります。

このプログラムには、"..{}".format(...), "...".join(...), "...".split()など文字列型データのメソッドが使われています。

まずはこの文字列型データのメソッドについて説明します。

文字列(str)型データのメソッド¶

pythonのデータ型を処理するための固有の関数(メソッド)が定義されています。 これらのメソッドはいくつかの種類に大きく分けることができます。

  • 文字列の内容を確認するためのメソッド:
    • .isascii(), .isdecimal(),.count(), .startwith()など
  • 文字列を操作するためのメソッド: 
    • .capitalize(), .center(), .strip(),.split(),.join()など
  • 文字列整形のためのメソッド:
    • .format(), .format_map()

今回は、これらのメソッドの内、よく使うであろう幾つかの関数についてご説明します。

今回説明を省いたメソッドについては、 Pythonの標準ドキュメントの

Python 標準ライブラリ テキストシーケンス型 --- str

などが参考になるでしょう。

データ型がどのようなメソッドを持っているかを覗くにはdir()関数を、そのメソッドのつかいかたは、help()関数を使うのは、手軽な方法だと思います。

メソッドの名前を忘れた時は...¶

dir()関数はオブジェクトあるいはクラスのメソッドあるいはアトリビュートのリストを返します。

Notes:¶

__で始まる名前には特別な意味があります。 これについてはいずれまた別のお話で。(今日のところは見なかった事に😁, 第11回「名前って何?」をご覧ください)。

In [2]:
print(dir(str)) # dir("") でもおなじ
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

関数に与える引数リストは?..¶

メソッドの名前だけでなく、使い方まで知りたい場合には、help()関数が役に立ちます。

In [3]:
help(str.center)
Help on method_descriptor:

center(self, width, fillchar=' ', /)
    Return a centered string of length width.
    
    Padding is done using the specified fill character (default is a space).

In [4]:
"フィボナッチ数の数表".center(77,"_")
Out[4]:
'__________________________________フィボナッチ数の数表_________________________________'

str型データはユニコード文字¶

Python3ではstr型は ユニコード文字が一列に並んだ物(ユニコード文字列)です。

ユニコード文字列定数 u"無限未来" と 文字列定数 "無限未来"は同じ同じ文字列を表します。

In [5]:
u"無限未来" == "無限未来"
Out[5]:
True
Notes:¶

python3ではstr型はUnicode文字列となっています。一方、python2では str型は1byte文字の並び(C言語と同じ)です。 python2とpython3の両方で働くスクリプトを作る際には、

python3: `unicode` == `str` != `bytes`

python2: `unicode` != `str` == 'bytes`

 エスケープシーケンス: ユニコード文字を文字名やコードポイントで指定する¶

エスケープシーケンス 意味
\N{name} Unicode データベース中で name という名前の文字
\uxxxx 16-bit の十六進値 xxxx をユニコード コードポイントに持つ文字
\Uxxxxxxxx 32-bit の十六進値 xxxxxxxx をユニコード コードポイントに持つ文字

ユニコード文字のコードポイントは、0x00〜0x10FFFFの範囲にあると規格により定義されています。

In [6]:
print ( "\N{RIGHT TRIANGLE}")
⊿
In [7]:
print("\\u{0:x}".format(ord("希")),"<->", "\u5e0c","<->","\U00005e0c")
\u5e0c <-> 希 <-> 希
In [8]:
import unicodedata
unicodedata.name("希"), "\N{CJK UNIFIED IDEOGRAPH-5E0C}"
Out[8]:
('CJK UNIFIED IDEOGRAPH-5E0C', '希')

Notes:¶

ord()関数は文字のコードポイントを整数として返します。 文字のユニコード上の名前は、unicodedataモジュールのname()関数を使って調べることができます。

encode()はバイト列に変換します。バイト列からdecode()を使ってユニコードに戻します。.encodeと.decodeのコード規則は一致している必要があります。

その他のエスケープ文字と raw 文字列定数 (r"")¶

タブ('\t')、改行('\n')などの制御文字を文字列中に挿入するためにエスケープ文字(エスケープシークエンス)を使います。エスケープ文字はほぼC言語と同じです。

エスケープシーケンス 意味 \ エスケープシーケンス 意味
\+newline バックスラッシュと改行文字が無視されます | \n ASCII 行送り(LF, NL, EOL, 0x0a)
\\ バックスラッシュ (\, REVERSE SOLIDUS, 0x5c) | \r ASCII 復帰 (CR, 0x0d)
\' 一重引用符 (', APOSTROPHE, 0x27) | \t ASCII 水平タブ (TAB, HT, 0x09)
\" 二重引用符 (", QUOTATION MARK,0x22) | \v ASCII 垂直タブ (VT, 0x0b)
\a ASCII 端末ベル (BEL, 0x07) | \ooo 8 進数値 ooo を持つ文字
\b ASCII バックスペース (BS, 0x08) | \xhh 16 進数値 hh を持つ文字
\f ASCII フォームフィード (FF, 0x0c) |

raw文字列定数( r"..."あるいは R"...")を使って、エスケープシーケンスの働きを抑制して文字列定数を定義できます。

In [9]:
s="abc\
de\\f"
tqs="""abc
de\\f
"""
print (s,repr(s))
print (tqs,repr(tqs))
print ("str:","ab\\nc", "raw str:", r"ab\\nc")
f"{{v}} {s}".format(v="xyz")
abcde\f 'abcde\\f'
abc
de\f
 'abc\nde\\f\n'
str: ab\nc raw str: ab\\nc
Out[9]:
'xyz abcde\\f'

.encode と .decode : ユニコード文字(str)とバイト列(bytes)の相互変換¶

通信、機器操作などでは、ユニコード文字列をバイト列として表現することが必要になります。python3では、バイト列を取り扱うためのデータ型としてbytes型が用意されています。

  • unicode文字列からバイト列への変換は、文字列型の.encode()メソッド。
  • バイト列からuncode文字列への変換は、 bytes型の.decode()メソッドを使います。
  • mutableなbytearray型も.decode()メソッドを持っています。

Notes:¶

bytes型はstr型と同じく不変(immutable)なデータ型です。一部を変更するためには、bytearray型が用意されています。

ユニコード文字列からbytesへ: .encode¶

In [10]:
u"新たな希望".encode("utf-8")
Out[10]:
b'\xe6\x96\xb0\xe3\x81\x9f\xe3\x81\xaa\xe5\xb8\x8c\xe6\x9c\x9b'

出力の文字列がb'あるいはb"で始まっているのは、これがbytes列型であることを表しています。

In [11]:
print("\\u{0:x}".format(ord("希")),"<->", "\u5e0c" )
print("\\u{0:x}".format(ord("希")), "!=", "希".encode('utf-8'),
      "!=", "希".encode('iso-2022-jp'),"!=", "希".encode('cp932'))
\u5e0c <-> 希
\u5e0c != b'\xe5\xb8\x8c' != b'\x1b$B4u\x1b(B' != b'\x8a\xf3'

Notes:¶

ord()関数は文字のコードポイントを整数として返します。 encode()はバイト列に変換します。バイト列からdecode()を使ってユニコードに戻します。.encodeと.decodeのコード規則は一致している必要があります。

bytesからユニコード文字列へ: .decode¶

bytes型データをユニコードに変換するには、.decodeメソッドを使います。

In [12]:
b'\xe6\x96\xb0\xe3\x81\x9f\xe3\x81\xaa\xe5\xb8\x8c\xe6\x9c\x9b'.decode("utf-8")
Out[12]:
'新たな希望'

joinとsplit:文字列の分解と結合¶

split:区切り文字で文字列を分解。¶

In [14]:
"来た、見た、勝った".split("、")
Out[14]:
['来た', '見た', '勝った']

join:区切り文字で文字列を結合¶

In [15]:
"!!".join(['来た', '見た', '勝った'])
Out[15]:
'来た!!見た!!勝った'

その他にも、.strip(),.justify(),.center(), .title, .upper(), .lower()などの文字列変換のメソッドが用意されています。これらのメソッドの戻り値は変換済みの新しい文字列です。 str型は不変(immutable)な型なので、これらの関数の実行で元の文字列は変更されずに、新しい文字列が作成されます。

In [16]:
s="abc"
print(s)
sc=s.center(40,"-")
print(sc)
abc
------------------abc-------------------

文字列の書式化:データの文字列化¶

プログラムからデータを端末などの出力するには、データを文字列化する(整形)ことが必要です。

Python3で文字列の書式化(整形)にはいくつかの方法があります。

  • Python3での基本は.formatメソッドでを使う方法です。

  • .format()をもっと簡単に使うために、フォーマット済み文字列定数(f"" あるいはF"")がPython3.6で導入されました

  • Python2で使われていた%-書式もまだ利用可能です。(†)

Notes¶

(†) python3で推奨されているのは、format書式をつかった方法です。

.format(): 書式指定文字列¶

参照: https://docs.python.org/ja/3/library/stdtypes.html#str.format

文字列型データの.format()メソッドは、C言語のsprintfとおなじように、 複数のデータから出力用の整形された文字列を作成します。

例えば、"{0:d}".format(123)は文字列'123'を作りだします。

In [17]:
"{0:d}".format(123)
Out[17]:
'123'

同じデータを異なった形式で整形することも可能です。ここでは、一つの引数を整数(d),浮動小数点(f)および指数形式(e)に 整形しています。(同じ入力データを書式指定文字列のなかで繰り返して使うことが可能です。)

In [18]:
"{0:d} {0:f} {0:e}".format(123)
Out[18]:
'123 123.000000 1.230000e+02'

.format関数の引数¶

.format関数には、変換対象となるデータを、位置引数あるいは名前付き引数として書き並べます。 変換指定文字列には引数に対応した {<指数>:<変換指定>} あるいは {<識別子>:<変換指定>} した変換指定文字列が含まれます。<指数> は .format に与えられた実引数の場所(0~)です。 変換指定文字列では"{"および"}"が特別の意味を持ちます。変換された後の文字列に{あるいは} が含む場合には、 "{{" あるいは "}}"をその場所で使います。

In [20]:
"{1:s} {0:d} {x:f}".format(123, "abc", x=3.14)
Out[20]:
'abc 123 3.140000'

同じ<指数>、<識別子>が複数回現れても良いのですが、現れる異なった指数は位置引数の数より小さくなくてはいけません。 また<識別子>は.formatの名前付き引数に現れていなければなりません。

同じデータを異なる変換指定を使うことで、異なった表現として印刷することができます。

In [21]:
"{0:d} {1:s}  {x:f} {y:f} {x:e} {y:e}".format(123, "abc", x=3.14, y=2.71)
Out[21]:
'123 abc  3.140000 2.710000 3.140000e+00 2.710000e+00'

変換指定文字列の一般型¶

<変換指定>は一般に次の形を持っています。

[[<フィル文字>]<整列指定>][<符号>][#][0][<幅>][<グルーピング指定>][.<精度>][<変換型>]


  • 変換指定の一般系の[]は省略可能な部分を示しています。 
  • <フィル文字>:任意の文字
  • <整列指定> : "<"(左詰), "^"(中央よせ), ">"(右詰), "="(符号と数字の間を指定された文字で埋める)
  • <符号> : "+", "-", " "
  • <幅> : 整形後の文字列の(最小の)長さ
  • <グルーピング指定>: 3桁ごとの区切り文字 "," または"_"
  • <精度>: 小数点以下の桁数
  • <変換型> :
    • 文字型  : "s"
    • 整数   : "b" | "o" | "x" | "X" | "c" | "d" |"n"
    • 浮動小数点: "e" | "E" | "f" | "F" | "g" | "G" | "%" | "n"

.format_map()関数¶

.format()では 引数に名前付き引数をつかうことで、変換指定文字列中で 出力するデータをその名前で指定することができました。

In [23]:
"{a} {b}".format(a=1,b=2)
Out[23]:
'1 2'

名前と値の組み合わせをすでに辞書型データとして持っているときには、.format_mapメソッドを利用できます。

In [24]:
d=dict(a=1,b=2)
"{a} {b}".format_map(d)
Out[24]:
'1 2'

Notes:¶

"{a} {b}".format(**d)
In [25]:
"{a} {b}".format(**d)
Out[25]:
'1 2'

フォーマット済み文字列定数 (f"...")¶

プログラム実行中に、定義済みの変数の値を印刷することはよくあります。たとえばこんな使い方です。

In [26]:
p=6.62607015e-34
"p={p:g}".format(p=p)
Out[26]:
'p=6.62607e-34'

フォーマット済み文字列定数を使うと、次の例のよう簡潔に記述することができます。

In [27]:
from numpy import sqrt
p=6.62607015e-34
f"{p=:g}"
Out[27]:
'p=6.62607e-34'

フォーマット済み文字列定数での式の利用¶

通常の書式指定文字列と同じようにフォーマット済み文字列定数(f"..." or F"...")では、{と}で囲まれた変換指定の部分が実行時のデータに基づいて置き換えられます。

  • フォーマット済み文字列定数では変換対象の指定は、変数の名前だけではなく、一般の式が許されます。
  • また、この式の後に=を追加することで、整形済みの文字列に式=の形の文字列が追加されます。
  • :以降の整形指定は書式指定文字列の場合と同様です。

Notes:¶

整形する対象となる式は、そのフォーマット済み文字列定数が定義されている環境で定義済みの変数などを組み合わせて作ります。

In [28]:
p=6.62607015e-34
f"p={p:g}, {p=:g}, {p**2=:g} {fib(5)=:d}"
Out[28]:
'p=6.62607e-34, p=6.62607e-34, p**2=4.39048e-67 fib(5)=8'

フォーマット済み文字列定数の使用例¶

フォーマット済み文字列定数を使って、数表印刷プログラムを書き換えてみます。

In [29]:
def 数表の印刷2():
    print ("{0:^73s}".format("フィボナッチ数の数表".center(40,"-")))
    print ( "   {0}".format(
        ",".join((f"     {c:02d}" for c in range(10)))))
    for r in range(0,30,10):
        print(f"{r:02d}:{{0:s}}".format(
            ",".join((f"{fib(c):7d}" for c in range(r,r+10)))
        ))
数表の印刷2()
                ---------------フィボナッチ数の数表---------------                 
        00,     01,     02,     03,     04,     05,     06,     07,     08,     09
00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55
10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765
20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040

新旧の比較¶

def 数表の印刷():
    print ("フィボナッチ数の数表".center(77,"_"))
    print ( "   {0}".format(
        ",".join(("     {0:02d}".format(c) for c in range(10))))
      )
    for r in range(0,30,10):
        print("{0:02d}:{1}".format(
            r,
            ",".join(("{0:7d}".format(fib(c)) for c in range(r,r+10)))
        ))
def 数表の印刷2():
    print ("{0:^73s}".format("フィボナッチ数の数表".center(40,"-")))
    print ( "   {0}".format(
        ",".join((f"     {c:02d}" for c in range(10)))))
    for r in range(0,30,10):
        print(f"{r:02d}:{{0:s}}".format(
            ",".join((f"{fib(c):7d}" for c in range(r,r+10)))
        ))

きょうのまとめ¶

今日の講座では、数表の印刷 を例に


  • 文字型(str)データのメソッド : .join(), .split() など

  • Unicode文字列(str)とバイト列(bytes) : u"abc" とb"abc"

    エスケープ文字列, raw文字列

    .encode(), .decode()

  • 文字列の整形(Format)

    str型の.format()メソッド

    フォーマット済み文字列定数: f""


などについて学びました。