{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "# 記録は美しく (Python入門講座第4回）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "`print()`関数は与えられた引数のデータ型に応じて文字に変換してくれます。\n",
    "しかし、数値を精度に応じた桁数で表示するなどデータを文字として出力する方法を\n",
    "制御する必要にすぐに直面するでしょう。\n",
    "\n",
    "ということで、今回は文字列（およびそれに関係したデータ型）の取り扱いについて学びます。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "目標は、\n",
    "\n",
    "```\n",
    "__________________________________フィボナッチ数の数表_________________________________\n",
    " 　   　   00,     01,     02,     03,     04,     05,     06,     07,     08,     09\n",
    "00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55\n",
    "10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765\n",
    "20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040\n",
    "```\n",
    "という形で数表を印刷することです。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "## きょうの目標\n",
    "\n",
    "今日の講座では、**数表の印刷** を例に\n",
    "\n",
    "* * * *\n",
    "- 文字型(`str`)データのメソッド : `.join()`, `.split()` など\n",
    "\n",
    "- Unicode文字列(str)とバイト列(bytes) : u\"abc\" とb\"abc\"\n",
    "    \n",
    "- 文字列の整形(Format)\n",
    "\n",
    "    str型の`.format()`メソッド\n",
    "\n",
    "    フォーマット済み文字列定数：　`f\"\"`\n",
    "* * * *\n",
    "\n",
    "などについて学びます。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "##　数表の印刷\n",
    "\n",
    "`n=0..29`のフィボナッチ数列`fib(n)`の値を次のような形で印刷するPythonプログラムを作って見ましょう。\n",
    "```\n",
    "__________________________________フィボナッチ数の数表_________________________________\n",
    " 　   　   00,     01,     02,     03,     04,     05,     06,     07,     08,     09\n",
    "00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55\n",
    "10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765\n",
    "20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__________________________________フィボナッチ数の数表_________________________________\n",
      "        00,     01,     02,     03,     04,     05,     06,     07,     08,     09\n",
      "00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55\n",
      "10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765\n",
      "20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040\n"
     ]
    }
   ],
   "source": [
    "#プログラムと実行結果\n",
    "def fib(n:int)->int:\n",
    "    if n == 0 or n == 1:\n",
    "        value= 1\n",
    "    else:\n",
    "        value= fib(n-1) + fib(n-2)\n",
    "    return value\n",
    "\n",
    "def 数表の印刷():\n",
    "    print (\"フィボナッチ数の数表\".center(77,\"_\"))\n",
    "    print ( \"   {0}\".format(\n",
    "        \",\".join((\"     {0:02d}\".format(c) for c in range(10))))\n",
    "      )\n",
    "    for r in range(0,30,10):\n",
    "        print(\"{0:02d}:{1}\".format(\n",
    "            r,\n",
    "            \",\".join((\"{0:7d}\".format(fib(c)) for c in range(r,r+10)))\n",
    "        ))\n",
    "        \n",
    "if __name__ == \"__main__\": 数表の印刷()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "#### Notes:\n",
    "fib()は前回と同じ定義を使います。\n",
    "\n",
    "数表を印刷する関数はたとえば、このようになります。\n",
    "\n",
    "このプログラムには、`\"..{}\".format(...)`, `\"...\".join(...)`, `\"...\".split()`など文字列型データのメソッドが使われています。\n",
    "\n",
    "まずはこの文字列型データのメソッドについて説明します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "## 文字列(`str`)型データのメソッド\n",
    "\n",
    "pythonのデータ型を処理するための固有の関数(メソッド）が定義されています。\n",
    "これらのメソッドはいくつかの種類に大きく分けることができます。\n",
    "\n",
    " - 文字列の内容を確認するためのメソッド:`.isascii()`, `.isdecimal()`,`.count()`, `.startwith()`など\n",
    " - 文字列を操作するためのメソッド：　`.capitalize()`, `.center()`, `.strip()`,`.split()`,`.join()`など\n",
    " - 文字列整形のためのメソッド: `.format()`, `.format_map()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "今回は、これらのメソッドの内、よく使うであろう幾つかの関数についてご説明します。\n",
    "\n",
    "今回説明を省いたメソッドについては、 Pythonの標準ドキュメントの\n",
    "\n",
    "[Python 標準ライブラリ テキストシーケンス型 --- str](https://docs.python.org/ja/3/library/stdtypes.html#text-sequence-type-str)\n",
    "\n",
    "などが参考になるでしょう。 \n",
    "\n",
    "データ型がどのようなメソッドを持っているかを覗くには`dir()`関数を、そのメソッドのつかいかたは、`help()`関数を使うのは、手軽な方法だと思います。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### メソッドの名前を忘れた時は...\n",
    "`dir()`関数はオブジェクトあるいはクラスのメソッドあるいはアトリビュートのリストを返します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "#### Notes:\n",
    "`__`で始まる名前には特別な意味があります。　これについてはいずれまた別のお話で。（今日のところは見なかった事に😁）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['__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']\n"
     ]
    }
   ],
   "source": [
    "print(dir(str)) # dir(\"\") でもおなじ"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### 関数に与える引数リストは？..\n",
    "メソッドの名前だけでなく、使い方まで知りたい場合には、`help()`関数が役に立ちます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on method_descriptor:\n",
      "\n",
      "center(self, width, fillchar=' ', /)\n",
      "    Return a centered string of length width.\n",
      "    \n",
      "    Padding is done using the specified fill character (default is a space).\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(str.center) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'__________________________________フィボナッチ数の数表_________________________________'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"フィボナッチ数の数表\".center(77,\"_\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "### `str`型データはユニコード文字\n",
    "Python3では`str`型は　ユニコード文字が一列に並んだ物(ユニコード文字列）です。\n",
    "\n",
    "ユニコード文字列定数　`u\"無限未来\"` と 文字列定数　`\"無限未来\"`は同じ同じ文字列を表します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u\"無限未来\" == \"無限未来\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "##### Notes:\n",
    "python3では`str`型はUnicode文字列となっています。一方、python2では `str`型は1byte文字の並び（C言語と同じ）です。　python2とpython3の両方で働くスクリプトを作る際には、\n",
    "\n",
    "    python3: `unicode` == `str` != `bytes`\n",
    "    \n",
    "    python2: `unicode` != `str` == 'bytes`\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "###　ユニコード文字を文字名やコードポイントで指定するためのエスケープシーケンス\n",
    "\n",
    "|エスケープシーケンス  | 意味 |\n",
    "|:---------------:|----:|\n",
    "|`\\N{name}` | Unicode データベース中で name という名前の文字 |\n",
    "|`\\uxxxx` |  16-bit の十六進値 xxxx をユニコード　コードポイントに持つ文字 |\n",
    "|`　\\Uxxxxxxxx` | 32-bit の十六進値 xxxxxxxx をユニコード　コードポイントに持つ文字|\n",
    "\n",
    "ユニコード文字のコードポイントは、0x00〜0x10FFFFの範囲にあると規格により定義されています。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "⊿\n"
     ]
    }
   ],
   "source": [
    "print ( \"\\N{RIGHT TRIANGLE}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\\u5e0c <-> 希 <-> 希\n"
     ]
    }
   ],
   "source": [
    "print(\"\\\\u{0:x}\".format(ord(\"希\")),\"<->\", \"\\u5e0c\",\"<->\",\"\\U00005e0c\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('CJK UNIFIED IDEOGRAPH-5E0C', '希')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import unicodedata\n",
    "unicodedata.name(\"希\"), \"\\N{CJK UNIFIED IDEOGRAPH-5E0C}\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "#### Notes:\n",
    "`ord()`関数は文字のコードポイントを整数として返します。\n",
    "文字のユニコード上の名前は、unicodedataモジュールの`name()`関数を使って調べることができます。\n",
    "\n",
    "`encode()`はバイト列に変換します。バイト列から`decode()`を使ってユニコードに戻します。`.encode`と`.decode`のコード規則は一致している必要があります。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### その他のエスケープ文字と　raw文字列定数 (`r\"\"`)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "タブ('\\t')、改行('\\n')などの制御文字を文字列中に挿入するためにエスケープ文字(エスケープシークエンス）を使います。エスケープ文字はほぼC言語と同じです。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "| エスケープシーケンス | 意味 |\\|| エスケープシーケンス | 意味 |\n",
    "|------:|:-----||-----:|:-----|\n",
    "|  `\\`+newline | バックスラッシュと改行文字が無視されます |\\||  `\\n`| ASCII 行送り(LF, NL, EOL, 0x0a) |\n",
    "|  `\\\\` |  バックスラッシュ  (`\\`, REVERSE SOLIDUS, 0x5c) |\\|| `\\r`| ASCII 復帰  (CR, 0x0d) |\n",
    "| `\\'` |  一重引用符 (', APOSTROPHE, 0x27) |\\|| `\\t`              | ASCII 水平タブ (TAB, HT,　0x09) |\n",
    "| `\\\"` | 二重引用符 (\", QUOTATION MARK,0x22) |\\|| `\\v`              | ASCII 垂直タブ (VT, 0x0b) |\n",
    "| `\\a` | ASCII 端末ベル (BEL, 0x07) |\\|| `\\ooo`            | 8 進数値 ooo を持つ文字 |\n",
    "| `\\b` | ASCII バックスペース (BS, 0x08) |\\|| `\\xhh`            | 16 進数値 hh を持つ文字 |\n",
    "| `\\f` | ASCII フォームフィード (FF, 0x0c) |\\|| | |\n",
    "\n",
    "raw文字列定数( `r\"...\"`あるいは `R\"...\"`)を使って、エスケープシーケンスの働きを抑制して文字列定数を定義できます。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "abcde\\f 'abcde\\\\f'\n",
      "abc\n",
      "de\\f\n",
      " 'abc\\nde\\\\f\\n'\n",
      "str: ab\\nc raw str: ab\\\\nc\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'xyz abcde\\\\f'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s=\"abc\\\n",
    "de\\\\f\"\n",
    "tqs=\"\"\"abc\n",
    "de\\\\f\n",
    "\"\"\"\n",
    "print (s,repr(s))\n",
    "print (tqs,repr(tqs))\n",
    "print (\"str:\",\"ab\\\\nc\", \"raw str:\", r\"ab\\\\nc\")\n",
    "f\"{{v}} {s}\".format(v=\"xyz\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "### `.encode` と　`.decode` :ユニコード文字(`str`)とバイト列(`bytes`)の相互変換\n",
    "\n",
    "通信、機器操作などでは、ユニコード文字列をバイト列として表現することが必要になります。python3では、バイト列を取り扱うためのデータ型として`bytes`型が用意されています。\n",
    "\n",
    " - unicode文字列からバイト列への変換は、文字列型の`.encode()`メソッド。\n",
    " - バイト列からuncode文字列への変換は、　`bytes`型の`.decode()`メソッドを使います。\n",
    " - mutableな`bytearray`型も`.decode()`メソッドを持っています。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "#### Notes:\n",
    "\n",
    "`bytes`型は`str`型と同じく不変（immutable)なデータ型です。一部を変更するためには、`bytearray`型が用意されています。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### ユニコード文字列から`bytes`へ: `.encode`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'\\xe6\\x96\\xb0\\xe3\\x81\\x9f\\xe3\\x81\\xaa\\xe5\\xb8\\x8c\\xe6\\x9c\\x9b'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u\"新たな希望\".encode(\"utf-8\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "出力の文字列が`b'`あるいは`b\"`で始まっているのは、これがbytes列型であることを表しています。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\\u5e0c <-> 希\n",
      "\\u5e0c != b'\\xe5\\xb8\\x8c' != b'\\x1b$B4u\\x1b(B' != b'\\x8a\\xf3'\n"
     ]
    }
   ],
   "source": [
    "print(\"\\\\u{0:x}\".format(ord(\"希\")),\"<->\", \"\\u5e0c\" )\n",
    "print(\"\\\\u{0:x}\".format(ord(\"希\")), \"!=\", \"希\".encode('utf-8'),\n",
    "      \"!=\", \"希\".encode('iso-2022-jp'),\"!=\", \"希\".encode('cp932'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "#### Notes:\n",
    "`ord()`関数は文字のコードポイントを整数として返します。\n",
    "`encode()`はバイト列に変換します。バイト列から`decode()`を使ってユニコードに戻します。`.encode`と`.decode`のコード規則は一致している必要があります。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### `bytes`からユニコード文字列へ: `.decode`\n",
    "\n",
    "`bytes`型データをユニコードに変換するには、`.decode`メソッドを使います。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'新たな希望'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b'\\xe6\\x96\\xb0\\xe3\\x81\\x9f\\xe3\\x81\\xaa\\xe5\\xb8\\x8c\\xe6\\x9c\\x9b'.decode(\"utf-8\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "### `join`と`split`：文字列の分解と結合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'abc       '"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"abc\".ljust(10).lstrip()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### split:区切り文字で文字列を分解。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['来た', '見た', '勝った']"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"来た、見た、勝った\".split(\"、\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### join:区切り文字で文字列を結合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'来た!!見た!!勝った'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"!!\".join(['来た', '見た', '勝った'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "その他にも、`.strip()`,`.justify()`,`.center()`, `.title`, `.upper()`, `.lower()`などの文字列変換のメソッドが用意されています。これらのメソッドの戻り値は変換済みの新しい文字列です。 `str`型は`不変(immutable)`な型なので、これらの関数の実行で元の文字列は変更されずに、新しい文字列が作成されます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "abc\n",
      "------------------abc-------------------\n"
     ]
    }
   ],
   "source": [
    "s=\"abc\"\n",
    "print(s)\n",
    "sc=s.center(40,\"-\")\n",
    "print(sc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "### 文字列の書式化:データの文字列化\n",
    "プログラムからデータを端末などの出力するには、データを文字列化する(整形）ことが必要です。\n",
    "\n",
    "Python3で文字列の書式化(整形）にはいくつかの方法があります。\n",
    "\n",
    "- Python3での基本は`.format`メソッドでを使う方法です。\n",
    "    \n",
    "- `.format()`をもっと簡単に使うために、フォーマット済み文字列定数(`f\"\"` あるいは`F\"\"`）がPython3.6で導入されました\n",
    "    \n",
    "- Python2で使われていた`%`-書式もまだ利用可能です。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "python3で推奨されているのは、format書式をつかった方法です。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "#### `.format()`: 書式指定文字列\n",
    "\n",
    "参照：　https://docs.python.org/ja/3/library/stdtypes.html#str.format\n",
    "\n",
    "文字列型データの`.format()`メソッドは、C言語のsprintfとおなじように、\n",
    "複数のデータから出力用の整形された文字列を作成します。\n",
    "\n",
    "例えば、`\"{0:d}\".format(123)`は文字列`'123'`を作りだします。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'123'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{0:d}\".format(123)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "同じデータを異なった形式で整形することも可能です。ここでは、一つの引数を整数(`d`),浮動小数点(`f`)および指数形式(`e`)に\n",
    "整形しています。(同じ入力データを書式指定文字列のなかで繰り返して使うことが可能です。）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'123 123.000000 1.230000e+02'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{0:d} {0:f} {0:e}\".format(123)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"'    123' '  123  ' '    123' '123'\""
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"'{output:>7d}' '{output:^7d}' '{output:>7d}' '{output:d}'\".format(output=123)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### `.format`関数の引数\n",
    "`.format`関数には、変換対象となるデータを、位置引数あるいは名前付き引数として書き並べます。\n",
    "変換指定文字列には引数に対応した`{<指数>:<変換指定>}` あるいは　`{<識別子>：<変換指定>}`\n",
    "した変換指定文字列が含まれます。\n",
    "変換指定文字列では\"{\"および\"}\"が特別の意味を持ちます。変換された後の文字列に`{`あるいは`}` が含む場合には、\n",
    "\"{{\"  あるいは　\"}}\"をその場所で使います。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'abc 123 3.140000'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{1:s} {0:d} {x:f}\".format(123, \"abc\", x=3.14)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "同じ<指数>、<識別子>が複数回現れても良いのですが、現れる異なった指数は位置引数の数より小さくなくてはいけません。\n",
    "また<識別子>は`.format`の名前付き引数に現れていなければなりません。\n",
    "\n",
    "同じデータを異なる変換指定を使うことで、異なった表現として印刷することができます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'123 abc  3.140000 2.710000 3.140000e+00 2.710000e+00'"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{0:d} {1:s}  {x:f} {y:f} {x:e} {y:e}\".format(123, \"abc\", x=3.14, y=2.71)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "## 変換指定文字列の一般型\n",
    "\n",
    "<変換指定>は一般に次の形を持っています。\n",
    "\n",
    "    [[<フィル文字>]<整列指定>][<符号>][#][0][<幅>][<グルーピング指定>][.<精度>][<変換型>]\n",
    "\n",
    "\n",
    "- 変換指定の一般系の`[]`は省略可能な部分を示しています。　\n",
    "- <フィル文字>:任意の文字\n",
    "- <整列指定> : \"<\"(左詰）, \"^\"（中央よせ）, \">\"（右詰）, \"=\"（符号と数字の間を指定された文字で埋める）\n",
    "- <符号> : \"+\", \"-\", \" \"\n",
    "- <幅> :　整形後の文字列の（最小の）長さ\n",
    "- <グルーピング指定>: 3桁ごとの区切り文字 \",\" または\"_\"\n",
    "- <精度>: 小数点以下の桁数\n",
    "- <変換型> ： \n",
    "  - 文字型　　： **\"s\"**\n",
    "  - 整数　　　： \"b\" | \"o\" | \"x\" | \"X\" | \"c\" | **\"d\"** |\"n\" \n",
    "  - 浮動小数点： \"e\" | \"E\" | \"f\" | \"F\" | **\"g\"** | \"G\" | \"%\" | \"n\"\n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'3.14 いろは ろ 1 xyz y a 3.140000 2.17 d'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from  datetime import datetime\n",
    "\n",
    "\"{v} {u} {u[1]} {0} {2} {2[1]} {1} {v:f} {w:g} d\".format(\n",
    "    1, \"a\", \"xyz\", \n",
    "    u=\"いろは\", v=3.14, w=2.17, z=None, d=dict(a=1,b=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "source": [
    "この例のように、出力データの1要素を取り出したり、そのアトリビュートだけを出力することもできます。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "#### `.format_map()`関数\n",
    "`.format()`では　引数に名前付き引数をつかうことで、変換指定文字列中で\n",
    "出力するデータをその名前で指定することができました。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1 2'"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{a} {b}\".format(a=1,b=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "名前と値の組み合わせをすでに辞書型データとして持っているときには、`.format_map`メソッドを利用できます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1 2'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d=dict(a=1,b=2)\n",
    "\"{a} {b}\".format_map(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "#### Notes:\n",
    "\n",
    "```python\n",
    "\"{a} {b}\".format(**d)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1 2'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{a} {b}\".format(**d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "### フォーマット済み文字列定数　(`f\"...\"`)\n",
    "プログラム実行中に、定義済みの変数の値を印刷することはよくあります。たとえばこんな使い方です。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'p=6.62607e-34'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p=6.62607015e-34\n",
    "\"p={p:g}\".format(p=p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "フォーマット済み文字列定数を使うと、次の例のよう簡潔に記述することができます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'p=6.62607e-34'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from numpy import sqrt\n",
    "p=6.62607015e-34\n",
    "f\"{p=:g}\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### フォーマット済み文字列定数での式の利用\n",
    "\n",
    "通常の書式指定文字列と同じようにフォーマット済み文字列定数(`f\"...\" or F\"...\"`)では、`{`と`}`で囲まれた変換指定の部分が実行時のデータに基づいて置き換えられます。\n",
    "- フォーマット済み文字列定数では変換対象の指定は、変数の名前だけではなく、一般の式が許されます。\n",
    "- また、この式の後に`=`を追加することで、整形済みの文字列に`式＝`の形の文字列が追加されます。\n",
    "- `:`以降の整形指定は書式指定文字列の場合と同様です。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "#### Notes:\n",
    "整形する対象となる式は、そのフォーマット済み文字列定数が定義されている環境で定義済みの変数などを組み合わせて作ります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'p=6.62607e-34, p=6.62607e-34, p**2=4.39048e-67 fib(5)=8'"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p=6.62607015e-34\n",
    "f\"p={p:g}, {p=:g}, {p**2=:g} {fib(5)=:d}\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### フォーマット済み文字列定数の使用例\n",
    "フォーマット済み文字列定数を使って、数表印刷プログラムを書き換えてみます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                ---------------フィボナッチ数の数表---------------                 \n",
      "        00,     01,     02,     03,     04,     05,     06,     07,     08,     09\n",
      "00:      1,      1,      2,      3,      5,      8,     13,     21,     34,     55\n",
      "10:     89,    144,    233,    377,    610,    987,   1597,   2584,   4181,   6765\n",
      "20:  10946,  17711,  28657,  46368,  75025, 121393, 196418, 317811, 514229, 832040\n"
     ]
    }
   ],
   "source": [
    "def 数表の印刷2():\n",
    "    print (\"{0:^73s}\".format(\"フィボナッチ数の数表\".center(40,\"-\")))\n",
    "    print ( \"   {0}\".format(\n",
    "        \",\".join((f\"     {c:02d}\" for c in range(10)))))\n",
    "    for r in range(0,30,10):\n",
    "        print(f\"{r:02d}:{{0:s}}\".format(\n",
    "            \",\".join((f\"{fib(c):7d}\" for c in range(r,r+10)))\n",
    "        ))\n",
    "数表の印刷2()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### 新旧の比較\n",
    "\n",
    "```python\n",
    "def 数表の印刷():\n",
    "    print (\"フィボナッチ数の数表\".center(77,\"_\"))\n",
    "    print ( \"   {0}\".format(\n",
    "        \",\".join((\"     {0:02d}\".format(c) for c in range(10))))\n",
    "      )\n",
    "    for r in range(0,30,10):\n",
    "        print(\"{0:02d}:{1}\".format(\n",
    "            r,\n",
    "            \",\".join((\"{0:7d}\".format(fib(c)) for c in range(r,r+10)))\n",
    "        ))\n",
    "``` \n",
    "\n",
    "```python\n",
    "def 数表の印刷2():\n",
    "    print (\"{0:^73s}\".format(\"フィボナッチ数の数表\".center(40,\"-\")))\n",
    "    print ( \"   {0}\".format(\n",
    "        \",\".join((f\"     {c:02d}\" for c in range(10)))))\n",
    "    for r in range(0,30,10):\n",
    "        print(f\"{r:02d}:{{0:s}}\".format(\n",
    "            \",\".join((f\"{fib(c):7d}\" for c in range(r,r+10)))\n",
    "        ))\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "## きょうのまとめ\n",
    "\n",
    "今日の講座では、**数表の印刷** を例に\n",
    "\n",
    "* * * *\n",
    "- 文字型(`str`)データのメソッド : `.join()`, `.split()` など\n",
    "\n",
    "- Unicode文字列(str)とバイト列(bytes) : u\"abc\" とb\"abc\"\n",
    "\n",
    "    エスケープ文字列, raw文字列\n",
    "    \n",
    "    `.encode()`, `.decode()`\n",
    "    \n",
    "- 文字列の整形(Format)\n",
    "\n",
    "    str型の`.format()`メソッド\n",
    "\n",
    "    フォーマット済み文字列定数：　`f\"\"`\n",
    "* * * *\n",
    "\n",
    "などについて学びました。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
