ラベル 文字列型 の投稿を表示しています。 すべての投稿を表示
ラベル 文字列型 の投稿を表示しています。 すべての投稿を表示

2012/12/06

文系のための「文字列型」(2)

「データ型」というのは、コンピュータを使う上で最も基礎的な知識の一つ。
それにも関わらず、初学者には理解しにくく、本を読んでも理解し難い。
最も良い方法は、実際にプログラムを書いてみること。

このブログの読者の中には、強い抵抗を感じる人も少ないかもしれないが、
プログラミングは、意外にも文系向けの技能。論理的思考ができれば誰でも書ける。
プログラマを目指す必要は無いが、少し書ければ、雑務はかなり減る。

別の仕事が増えても責任を取ることはできないが...。

とは言うものの、このブログの目的は、プログラムの話では無いので、
プログラムの書き方を知らない人のことを考えて可能な限り平易に書くように努める。
比較的簡単なプログラミング言語にPythonというものがある。以下ではこれを用いる。

公式サイトは、http://www.python.org/ 。ここで、ダウンロードできる。
もちろん、無償で入手できる。注意すべきはバージョン。
インストールするべきは、「2.x」。このブログ執筆時には「2.7」。

とにかく「Python 2.7 」をインストール。

「2.x」と「3.x」はかなり違う。間違えると以下の処理ができないかもしれない。
この二つのバージョン、現在でも、同時並行で使われている。
「3.x」の方が最新バージョン、という訳では無いので注意。

Python のインストール方法は、探せば丁寧な説明は多く存在するはず。
Google検索で「Python2.7 インストール方法」などと検索するのが良い。
私が説明するよりも解りやすい説明をしている人がいるはず。

さて、ここから先は、インストールをしていることを前提に話を進める。
もちろん、インストールして無くても良いのだが、
折角の機会でもあるし、まだの人はインストールすることを進める。

以上の準備が完了したら、Python を起動する。
Windows の人は、IDLE(Python GUI) というプログラムをし、
MacとUbuntu の人は、Terminal(端末)上で Python と入力して実行する。

とりあえず、画面上に「>>>」という記号が表示してあって、
その横で「|」が点滅している状態であれば大丈夫。
この状態はコマンドの待機状態。コンピュータに命令できる状態。

この画面を「コンソール画面」と呼ぶ。
では、Pythonにおける「文字列型」の話を続けることにしよう...。

PostgreSQL の文字列型とPythonの文字列型は、当然ながら異なるのであるが、
「データ型」を理解するには、様々な環境下のデータ型を理解しておいた方が良い。
なお、データ型の定義は、PostgreSQL の方が「厳密」。Pythonはかなり「甘い」。

PostgreSQLでは4種類の文字列型が存在したが、Python では1種類のみ。
Python の文字数限界は、半角英数の場合で「1,073,741,824」文字まで格納でき、
日本語など全角文字の場合では「536,870,912」文字まで格納できる。

このような「性能上」の違いはあるが、基本的な処理の仕組みは同じ。
もちろん、文法上の違いはあるが、仕組みを理解できれば今は良い。
Python から PostgreSQL を直接的に操作できるのだから、両方知っておいた方が良い。

さてさて、今回は、初っ端から話が脱線しっぱなしである。話を元に戻そう。
今回の話では、「文字列型」基礎的な性質と簡単な演算について理解する。
実は、数値と同じように「文字列型」にも様々な演算が存在している。

とりえあえず、練習から。コンソールに以下の3行をコピーし、
深く深呼吸してから、Pythonのコンソール画面に貼り付ける。
コピー&ペーストの作業は、マウス操作で行った方が良い。

"Hello"
'Hello'
Hello

すると、以下のような出力が得られるハズ。
何も恐れる必要は無い。別にパソコンが壊れる訳ではない。
日本語のメッセージに置き換わっているかもしれないが同じ内容。

>>> "Hello"
'Hello'
>>> 'Hello'
'Hello'
>>> Hello
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'Hello' is not defined

最初の二行は実行した行の下に 'Hello' というのが表示され、
最後の一つには、何やら、怪しげなメッセージが表示されている。
落ち着いて最後の三行を見てみる。

一行目は、このメッセージの直前の処理から何かのエラーが帰ってきたことを示す。
二行目は、このメッセージが直前の処理の何行目でエラーが発生していたことを示す。
三行目は、このメッセージが伝えているエラーの種類を示している。

NameError: name 'Hello' is not defined

要するに「ネームエラー(Name Error)」というのが出ている。
では、「'Hello' という名前は定義されていません」どういう意味か?
実は、「"」あるいは「'」で囲まれていない文字列は「変数」として認識される。

つまり、プログラム上では、「"」あるいは「'」で囲まれている部分が、
「文字列」として扱われているのである。コンピュータ上では非常に重要な記号の一つ。
ちなみに、現段階では「"」と「'」は、どちらを用いても良い。使い分けはいずれ。

さて、この表記方法、Python に限ったことでは無い。
なんと、あのエクセルでも同じ。エクセルにID番号として「12-12-01」のようなものを入れると、
勝手に「2012年12月1日」というように日付に変換されたことは無いだろうか?

これは、エクセルが入力されたデータから自動的にデータ型を推測し、
「どうやら、このデータは日付型らしい」という判断をした結果である。
この問題に頭を抱えている人を見かけることは少なくない。

実は、この問題の回避する手段は非常に簡単である。
「'12-12-01」のように、最初に「クォーテーション」を付けて入力すれば良い。
すると、文字列と認識され、実際には「'12-12-01'」として扱われる。

さて、このことを確認できたら、次に「文字列型」の四則演算から実験してみる。
何も考え無くても良いので、以下の4行をコピーして、コンソール画面に貼り付ける。

"Hello" + "World"
"Hello" - "World"
"Hello" * "World"
"Hello" / "World"

すると、以下のような出力が得られる。エラーも出ている。

>>> "Hello" + "World"
'HelloWorld'
>>> "Hello" - "World"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> "Hello" * "World"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'str'
>>> "Hello" / "World"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'str'

さて、コピーした4行というのは、"Hello" と "World" の演算である。
要するに、足し算、引き算、掛け算、割り算の3つの計算を一処理ずつ実行している。
さて、この出力を見て気になるのはエラーの部分。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'str'

最初の二行はさっきのエラーと同じ。最後のメッセージ行のみが重要となる。
ここで「str」とは、「string」の略で、Pythonの「文字列型」を表すので、
「文字列 」と「文字列」の計算において、対応していない演算(記号)が使われたのがエラーの原因。

さて、ここでクイズ。上記4つの処理の中で、唯一このエラーが発生していないのはどれか?
4行分をコピーして実行したのであるが、1処理ずつ実行していることも重要。

>>> "Hello" + "World"
'HelloWorld'

これが答え。エラーを示す三行のエラーメッセージの代わりに、
"HelloWorld" という文字列が表示されている。
以上のことから、文字列は、足し算することができることが解る。

前回の話でも解説したが、「文字列」というのは「文字」の配列である。
つまり、"Hello" という5文字の配列と、 "World"という5文字の配列を足すことができる。
その結果が "HelloWorld"である。このように考えると他の演算が出来ないことも納得できる。

さて、では、以下のような演算は可能であろうか?同様にコピペ。

"Hello" - 4
"Hello" * 4
"Hello" / 4

この演算結果は以下の通り。

>>> "Hello" - 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'int'
>>> "Hello" * 4
'HelloHelloHelloHello'
>>> "Hello" / 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'int'

先程と同様に、この中で一つだけエラーが出ていない命令がある。どれか?
答えは、「"Hello" * 4」の計算。これは、"Hello"という配列が4つという意味。
したがって、'HelloHelloHelloHello' という結果が表示されているのである。

さて、ここでも、エラーを確認してみる。見るべき部分は三つ目の行。
今度は「int」というのが出てきている。これは「整数値型」を意味する。
つまり、文字列と整数値の演算において対応していない演算が行われたことを意味する。

以上のことから、文字列同士の演算は、「足し算」のみが可能であり、
また、文字列と整数値の演算は、「掛け算」のみが可能である。

さて、これで「メデタシ、メデタシ」とはいかない。
実は、文字列と整数値の足し算をまだ実験していない。
この処理、ちょっと、変わった結果になるからである。

"Hello" + 4

というのを実行してみると、以下のようなエラーが出る。

TypeError: cannot concatenate 'str' and 'int' objects

よく見ると、エラーメッセージの内容が先ほどと異なる。
「文字列と整数値をくっつけることができません」と言っている。
つまり、演算としては存在するが、整数型を文字列に足すことはできないのである。

そうそう。同じ「数」であっても「数値」と「数字」は異なるのであった。
では、プログラミング上で文字列を認識するには、どうすれば良かったのか?
「"」あるいは「'」で囲めば良かった。ではやってみる。

"Hello" + "4"

これを実行すると以下のようになる。

>>> "Hello" + "4"
'Hello4'

すると、"Hello" という5文字の配列と"4"という1文字の配列の足し算となり、
この二つをくっつけた文字列として'Hello4'が表示されるのである。
このようにして、文字列を結合することができるのである。

別の考え方もできる。先程は、文字列としての「数」を表すという考え方であったが、
整数型を文字列型に変換するという考え方もできるハズ。
このようなデータ型の変換のことを「キャスト」と呼ぶ。

"Hello" + str(4)

このようにすると、4という数値は、strという文字列型に変換される。

>>> "Hello" + str(4)
'Hello4'

もちろん、結果は先程と同じ'Hello4'である。
なるほど、段々と状況が読めてきた。では、最後に、以下の演算を実験してみる。
以下の3つの計算、実行前に計算結果を予測できるだろいうか?

256 + 256
"256" + "256"
str(128) * 3

では、答え合わせ。実行してみると以下の通りになる。

>>> 256 + 256
512
>>> "256" + "256"
'256256'
>>> str(128) * 3
'128128128'

さて、予想通りの結果になったであろうか?

コンピュータ上では、数値と数字は異なるということと、
文字列の足し算と掛け算が配列に対して行われているということ、
この二つのことが理解できていれば、簡単に予測できたことであろう。

文系のための「文字列型」(1)

コンピュータで扱う情報は「1」と「0」。そのようなデータをデジタルデータと呼ぶ。
デジタルデータには、様々な「型」があって、その「型」に応じた処理が行われる。
ここまでの話を整理すると、ざっと、こんな感じである。

さて、今回は、様々な「データ型」の中で、利用頻度が高い「文字列型」について。
おそらく、一般的なユーザが最も頻繁に用いている「型」かもしれない。
もちろん、現在、書いているブログの文章も「文字列型」で構成されている。

まずは、「文字列型」とは何かについて考えてみる。

すでに、述べたように、コンピュータ上で扱う「文字」は、
たとえ数字であったとしても、何らかの「対応表」を参照していて、
その対応表の場所を「2進数」で示しているのであった。

こうして対応表を通して「2進数」で記述することを「符号化」と呼び、
「符号化」された1文字を「文字型」、これを「配列」にしたものを「文字列型」と呼ぶ。
プログラミング言語の中には、「文字型」しか持たないものもある。

さて、今回は「文字列」の限界、すなわち、「文字数限界」について考えてみる。
実は、コンピュータで扱える「文字数」には限界がある。
もちろん、エクセルの一つのセルに入力できる文字数にも限界がある。

このことは、データベースを自分で構築する際の最も重要な知識の一つであり、
また、エクセルなどで比較的長い文字を扱う人は理解しておいた方が良い。
特に、文献資料等の文字資料を扱う人は注意すべきで問題である。

では、早速、PostgreSQL9.1における「文字列型」を見てみる。
  1. character あるいは char
  2. character(n) あるいは char(n)
  3. character varying(n) あるいは varchar(n)
  4. text
実は、PostgreSQL 9.1 では、以上の4つの「文字列型」が存在している。

一つ目は、いわゆる「文字型」つまり、1文字だけ格納可能な型。
二つ目は「固定長文字列型」、三つ目は、「可変長文字列型」であり、
そして、四つ目は「テキスト型」と呼ばれている。

見方が解らない人が居るかもしれない。ということで、まずは、表示方法について。
括弧が付いている場合は、「()」の所までが「型名」で、
「()」の中が「引数(パラメータ)」であり、この型の「限界値」である。

「限界」というのは、この文字列の配列の数を表していて、
「n」には、配列の長さをあらわす「1つの整数値」が入る。
つまり、「n」は、「文字数の限界」を決めるための「変数」である。

また、「可変長」と「固定長」というのは、この「文字数の限界」に関係していて、
「可変長」の場合は、この「型」に入っている文字列の長さが文字の数に依存し、
「固定長」の場合は、この「型」に入っている文字列の長さはその限界の数である。

要するに、「可変長型文字列」と「固定長文字列型」は文字数を決めないといけない。
一方、「character」と「text」には、「()」が付いていないので、
この型については、引数が不要であることを示している。

例えば、「人名」を「10文字(20bite)」の「文字列型」で指定し、
この型に対応する値として「新島 襄」という値を入力するとする。
この時、それぞれの型ではどのようになるか?

・文字型の場合  :"新"
・可変長の場合  :"新島□襄"
・固定長の場合  :"新島□襄□□□□□□"
・テキスト型の場合:"新島□襄"

「文字型」の場合、「1文字」しか受け付けないので、「新」以降は切り捨てられる。
「可変長」と「テキスト型」の場合は、同じで、入力した通りに値が入る。
そして、「固定長」の場合には、10文字になるまで「空白(□)」で埋める。

もしも、10文字以上の名前が存在したらどうなるのか?
これも考えてみる。もっと長い名前と言えば...「寿限無」?
といことで、寿限無を入力してみる。

・文字型の場合  :"じ"
・可変長の場合  :"じゅげむ□じゅげむ□"
・固定長の場合  :"じゅげむ□じゅげむ□"
・テキスト型の場合:"じゅげむ□じゅげむ□ごこうのすりきれ
          かいじゃりすいぎょの□すいぎょうまつ
          うんらいまつ□ふうらいまつくうねると
          ころに□すむところ□やぶらこうじの□ぶ
          らこうじ□ぱいぽぱいぽぱいぽのしゅー
          りんがん□しゅーりんがんのぐーりんだ
          い□ぐーりんだいのぽんぽこぴーのぽん
          ぽこなーのちょうきゅうめいのちょうす
          け"

このようになる。「テキスト型」のみは全ての文字を格納できるが、
「文字型」は1文字のみ、「可変長」と「固定長」はともに10文字の限界があるので、
超過した部分は切り捨てられる。

通常は意識したことは無いであろうが、
実は、このような「文字数の制限」というのは、
データベースに限らず、様々な所で出てくる問題である。

なぜ、このように複雑な定義が必要なのか?

最近のコンピュータは、性能が高いので意識することは「少ない」が、
コンピュータのメモリやCPUの負担を少なくするための工夫が現れているのである。
ちょっと大きなデータを扱うと、最新のコンピュータでも処理が追いつかないのである。

ちなみに、少し前までは、引数「n」に指定できる限界値は非常に小さく、
「128文字(bite)」あるいは、もう少し大きくて、「256文字(bite)」であった。
かつては、限られた資源を上手く使い回すのが腕の見せ所だった。

なお、PostgreSQL 9.1 では、最大で1GBまでサポートされている。
単純に計算すると、2バイト文字で非圧縮の場合4096文字程度まで格納できる計算である。
これよりも長い「文字列」を扱う時には、ちゃんと、仕様書を確認した方が良い。

実際には、文字列を圧縮するようなので、もう少し格納できるかもしれない。
「文字数限界」については、深く知ろうとすると色々と厄介なのでここでは割愛。
いずれにせよ、長大な「文字列」を扱う際には注意が必要である。

次回は、Python というプログラミング言語を通して、
もう少し、文字列型の性質や操作について考えてみる。