文字列

これまでに登場した文字列型の説明

教科書 Lesson 9.1

これ以降は、教科書の Lesson 9.1 の作業を進めてください。9.1 だけ、です。それが済めばすぐ次にある「確認課題」に進んでください。

おさらい

扱った内容を以下に列挙しておきます。ここに書かれていることが理解出来ますか?

文字列のリスト

この授業では飛ばした 5.6 「リスト要素の組み合わせと分解」(p.122)で、「リストに文字列を入れられる」ことがシレッと出ています。

city = ["東京", "名古屋", "大阪", "京都"]

Python のリストでは、要素は数値でも文字列でもなんでも混在させられます。この教科書ではあまり登場しませんが、文字をリストで扱うことはよくあります。

教科書に出ていないが有用そうなこと

教科書に出ていないが重要な型変換のこと

これまで数値の入力は num = int( input( ) ) などと書いていましたが、それは input( ) が文字列を返すからです。つまり文字列 “123” に対して計算すること(例えば “123” + 1 など)はできず、“123” を数値の 123 に変換してから +1 する必要があります。

int( ) 関数は引数に与えられたデータを整数に変換するものです。例えば int( “123” ) とすると数値 123 が得られます。つまり int( “123” ) + 1 と書けば計算の結果として 124 が得られます。

ところで int( ) は小数点を含んだ文字列を与えるとエラーになります。実数に見える文字列を実数データに変換するのは float( ) 関数です。float( “123.4” ) とすると数値 123.4 が得られます。

逆に数値を文字列化するのは str( ) 関数です。つまり str( 123 ) と書くと文字列 “123” が得られます。

そのデータが文字列なのか数値なのか、つまり種類によって実行可能な処理内容は変わるはずです。このデータの種類のことを「型(かた)」あるいは「データ型」と呼んでいます。つまり int( ) や str( ) はデータの型変換を行う関数なのです。

int( ) に与えられるのは文字列だけではない
ところで float( “123” ) とすると数値 123.0 が得られます。もし整数 123 が欲しい場合は int(float( “123” )) とすると良いです。int( ) は結局「整数化」関数であり、int( ) の引数には文字列だけでなく実数のデータも与えられます。例えば計算結果の小数点以下を切り落として整数化したいときなどに(普通に)使います。

教科書に出ていないが重要な文字コードのこと

「コンピュータ概論」科目のごく初めの週に、データの符号化のことを扱いました。どのような情報も、コンピュータの中ではデータ、つまり「何らかの方法で符号化された値」として扱われています。文字のコードについては ASCII コードを紹介されたと思います。以下のスライドで思い出せますよね。

image-20231109003838838

Python で扱う文字も、コンピュータの内部ではこうした文字コード(値)として扱われています。例えば “A” も、ord( ) 関数を使うとその値を得ることができます。

>>> print( ord("A") ) 
65
>>> 

左上のスライドにあるとおり、“A” は 65 ですね。

このことを頭に置くと「文字は大小比較ができる」ことがわかるでしょうか。つまり、“A” < “B” のような比較ができるのです。以下のような結果になります。

>>> "A" < "B"
True
>>> "A" > "B"
False
>>>

つまり “A” は “B” より「小さい」のです。これは「文字そのものに概念的な大小関係がある」といったことではなく、「文字の大小比較は、値(文字コード)の大小比較だ」ということです。

すなわち、“A” < “b” も True になります。“A” のASCIIコードは 65、“a” は 97 だからです。以下の比較の結果(True / False)がすべて納得いくでしょうか。

>>> "A" == "A"   # A と A は「同じ」
True
>>> "A" == "a"   # 大文字の A と小文字の a は「同じではない」
False
>>> "A" < "a"    # 大文字の A と小文字の a では、小文字の a の方が「大きい」
True
>>> "B" < "a"    # 大文字の B と小文字の b でも、小文字の a の方が「大きい」
True
>>> 

教科書に出ていないが有用そうな .format() の書式設定のこと

教科書 p.261 あたりに出てくる .format() の使い方はかなり限定的です。もし興味がある人は 書式指定 を見ると良いでしょう。

確認課題

課題1. 文字種判定

入力された文字列(ただし1バイト文字限定、つまりASCIIコード範囲内)について、英字・数字・それ以外の文字数をそれぞれカウントするプログラムを作って下さい。「 abc=1+2 」と入力すると「alpha = 3 number = 2 other = 2」と表示するのです。

step 1. 文字列をリストにする

入力した文字列を文字に分解して表示するコードを示します。

string = input()
string_list = list(string)
print(string_list)

このプログラムを実行して動作を確認して下さい。例では実行後に「test 123」と入力しています。文字ごとに分解されてリストとなっていることがわかります。

yasuda@Cecil 12 % python3 asciiCheck.py
test 123             <<< test 123 と入力した
['t', 'e', 's', 't', ' ', '1', '2', '3']
yasuda@Cecil 12 % 

step 2. 文字種の判定とカウント

このプログラムに、それぞれの文字の種類が英字か、数字か、それ以外かを判定するコードを追加し、その結果を数え上げて最後に出力するようにしてください。

yasuda@Cecil 12 % python3 asciiCheck.py
test 123 
['t', 'e', 's', 't', ' ', '1', '2', '3']
alpha = 4 number = 3 other = 1
yasuda@Cecil 12 % 

もし対象の文字が、“A”〜“Z” あるいは “a”〜“z” の範囲にあれば英字です。これは文字の大小比較で調べることができますね。数字も同様に “0”〜“9” の間にあることを確認すれば良いです。

英字が 4 文字(“test”)、数字が 3 文字(“123”)とそれ以外が 1 つ(空白がありましたね)と、正しく数えられている事が確認できますね。

Love & Peace, Rock'n'Roll

と入力したとき、正しく「alpha = 18 number = 0 other = 7」と答えるでしょうか?

step 3. 境界テスト

この種のプログラムが「どのような入力でも正しく動作する」ことを確認するのは容易ではありません。パッと思いつく動作確認方法は以下のような方法でしょうか。

  1. 思いついた文字列を入力し、手作業で数えてみたものと結果が一致することを確認する
  2. ありとあらゆる文字列を片端から試す

この 1. と 2. の中間的なテスト、つまり現実的な工数で、まあまあの確からしさが期待できる方法が必要です。例えばこの例題のような場合は「境界テスト」が良いです。

境界テストとは、その処理の仕様上の境界値(つまり条件判定に用いる値)の前後のデータを与え、そのどちらの場合でも正しく動作することを確認するものです。つまり if a < 100: と条件設定されている場合、a の値が 99 と 100 の時で挙動が変わりますから、a が 99 と 100 になるような入力をプログラムに与えます。

今回たとえば数字の判定が “0” 以上 “9” 以下となっていますから、“0” の一つ前の文字コードを持つ “/” と、“9” の一つ後の “:” (コロン)を含む、つまり「 /09: 」という入力を与えて「数字の判定」が正しくできていることを確認します。英字についてもそのようにしてテストしましょう。特に “Z” より大きく、“a” より小さい文字は英字ではありません(記号です)から、そこのチェックは重要です。

そのようにして動作確認できたら Moodle に提出してください。

補足:文字種判定メソッド

Python には .isalpha( ) など文字種を判定するメソッドがあります。ただ今回の例題は文字コードを意識するためのものなので、それらの関数は使わず作って下さい。なお使うときには isnumeric( ), isdecimal( ), isdigit( ) などの酷似した処理の違いなど、しっかり調べてから使いましょうね。

課題2. 回文ふたたび

前回は数値データをリストに入れて回文判定をしましたが、今回はストレートに文字で「きいろいき(黄色い木)」や「やすいいすや(安い椅子屋)」を判定させられます。

アルゴリズムとしては前回同様、以下の方法でやりましょう。

  1. 与えられた文字列を前半分と後ろ半分に分割する
  2. 後ろ半分の文字列を逆順に並べ替える
  3. 二つの文字列を比較する
  4. 一致していたら “Anagram”、一致していなければ “Not Anagram” と出力する

課題1. と同様に、この2行からプログラムを始めてください。これで1行の echo 文で入力した数字列がリストになります。

input_str = input()
print(input_str)

意識すべきことについて列挙しておきます。

上のコードに、はじめに示したアルゴリズム(文字列の分割・並べ替え・比較)の処理を追加して、以下のような出力をするプログラムとして完成させてください。

yasuda@Slack 12 % echo "きいろいき" | python3 sAnagram.py
Anagram
yasuda@Slack 12 % echo "これはだめ" | python3 sAnagram.py
Not Anagram
yasuda@Slack 12 % 

およそ動作する、と思える状態になったら、Web 教材にあるテストスクリプト sAnagram.sh を実行して動作を確認してください。

見ての通り最初の 5 例が回文、次の 3 例が回文ではないもの、です。

# 前半は Anagram
echo "い" | python3 sAnagram.py
echo "いえい" | python3 sAnagram.py
echo "なるととるな" | python3 sAnagram.py
echo "まさかさかさま" | python3 sAnagram.py
echo "まつたけつみにきてきせきてきにみつけたつま" | python3 sAnagram.py
# 後半は非 Anagram
echo "いえ" | python3 sAnagram.py
echo "いええ" | python3 sAnagram.py
echo "いえいえ" | python3 sAnagram.py

実行すると以下のように、5 つ Anagram、3 つ Not Anagram と並ぶはずです。

yasuda@Slack 12 % zsh sAnagram.sh                                                        
Anagram
Anagram
Anagram
Anagram
Anagram
Not Anagram
Not Anagram
Not Anagram
yasuda@Slack 12 % 

ここまで確認できたら Moodle に提出してください。