Python.use(better, by="k&r") 伝統的な制御構造に代わる for 文を使って 同等の関数 atoi を実現できます # for novice 6 atoi 1 文字列から整数を得るには 伊藤うさぎ Python には 組み込み関数 int() があるので atoi() を実現するには及びません しかし 同等の機能を実現してみるのも一興です 6 では K&R を模倣したもの を 7 8 では Python ならでは実現方法を示します 3.5 節では 標準ライブラリー関数 int atoi(const char *s) を模して 文字 列を int 型の値に変換する事例を紹介しています!K&R, p.61" #include <ctype.h> int atoi(char s[]) { int i, n, sign; for (i = 0; isspace(s[i]); i++) ; sign = (s[i] == '-')? -1 : 1; if (s[i] == '+' s[i] == '-') for (; isdigit(s[i]); i++) n = 10 * n + (s[i] - '0'); ; /* skip white space */ /* skip sign */ K&R, p.61 "The structure of the program reflects the form of the input:" と あるように プログラムの構造は 入力形式を反映した ものとなります 1 空白文字を読み飛ばして 2 符号を取り出して 3 整数部を変換する という段階を経て 文字列を整数値に変換します このとき 整数に変換できない文字 が出てきたら そこで処理を中断します 標準ライブラリー関数 isspace(c) は空白文字かどうかを isdigit(c) は十進数 字かどうかを判定して その結果が真なら非零の値を 偽なら 0 を返します C言語における for 文は ループ変数を使って 任意の要素を順に処理したいとき に多用されます たとえば for (i = 0; i < n; i++) というコードの断片は n 個の要素を順に処理するという 典型的なイディオムの1つです Python では この i = 0 if not e.isspace(): break if s[i] == "-": sign = -1 else: sign = 1 if s[i] == "+" or s[i] == "-": n = 10*n + (ord(e)-ord("0")) # skip white space # skip sign Python における for 文は コレクション内の各要素を順に処理したいときに多用 されます たとえば というコードの断片は 文字列 s 内の各文字 e を順に処理するという 典型的なイディオムの1つです str 型の文字列に対して isspace() は空白文字かどうかを isdigit() は十進数 字かどうかを判定して 文字列を構成するすべての文字が条件を満たすなら True を 条件を満たさない文字が1つでもあるなら False を得ます 1 空白文字 e を読み飛ばすごとに 変数 i の値が1つずつ増えます その文字 が 空白文字 not e.isspace() でないとき for ルーブから抜けます 2 符号を取り出したときには その値を変数 sign に保持します 3 整数部を変換するときには 部分文字列 s[i:] が対象となります 組み込み関 数 ord(c) を使って 各文字 c に対応する ASCII コードの値を獲得します その文字 が 数字 not e.isdigit() でないとき for ルーブから抜けます C言語では 文字列の末尾に '\0' があるので これを for ルーブから抜けるとき の条件式に利用できます Python では 文字列の内部表現を気にする必要がなく for 文を使って 情報隠蔽 を実現できます ひよ子のきもち 2007/06/11
i = skip_white_space(s) sign = get_sign(s, i) i = skip_sign(s, i) skip_white_space get_sign, skip_sign convert_int isign n def skip_white_space(s): i = 0 if not e.isspace(): break return i def get_sign(s, i): if s[i] == "-": sign = -1 else: sign = 1 return sign def skip_sign(s, i): if s[i] == "+" or s[i] == "-": return i def convert_int(s, i): n = 10*n + (ord(e)-ord("0")) s = skip_white_space(s) sign = get_sign(s) i = skip_sign(s, 0) def skip_white_space(s): return s.strip() strip() def get_sign(s): return (1, -1)[s.startswith("-")] startswith(prefix) prefix True/False 1/0 1/0?: "-" def skip_sign(s, i): return s[i] in "+-" in True/False 1/0 1/0 +/-
n = convert_int(s, s[0] in "+-") strip startswith, in convert_int atoi convert_int s = skip_white_space(s) sign = get_sign(s) i = skip_sign(s, 0) '\0' for atoi atof
int double(const char *s) double!k&r, p.71" #include <ctype.h> double atof(char s[]) { double val, power; int i, sign; for (i = 0; isspace(s[i]); i++) /* skip white space */ ; sign = (s[i] == '-')? -1 : 1; if (s[i] == '+' s[i] == '-') for (val = 0.0; isdigit(s[i]); i++) val = 10.0 * val + (s[i] - '0'); if (s[i] == '.') for (power = 1.0; isdigit(s[i]); i++) { val = 10.0 * val + (s[i] - '0'); power *= 10.0; return sign * val / power; atoi() atof() def atof(s): val = convert_int(s, s[0] in "+-") val, power = convert_fraction(val, skip_point(s, ".")) return sign * val / power skip_point convert_fraction atoi atof convert_fraction def convert_int(s, i): n = 10*n + decimal(e) decimal() def skip_point(s, dot): ss = "" if dot in s: ss = s.split(dot)[1] return ss split(sep) sep 1 "." "" def convert_fraction(v, s): val, power = v, 1.0 val = 10.0*val + decimal(e) power *= 10.0 return val, power convert_int v val, power
def decimal(n): return ord(n)-ord("0") convert_int/skip_point/convert_fraction convert_int 0 skip_point "" convert_fraction v1.0 def atof(s): integer, fraction = split_point(s, sign="+-", dot=".") val = convert_integer(integer) val, power = convert_fraction(val, fraction) return sign * val / power atof() def split_point(s, sign, dot): s = skip_sign(s, sign) # Please, look at me! integer, fraction = s, "" if dot in s: integer, fraction = s.split(dot) return integer, fraction def skip_sign(s, sign): return s[s[0] in sign] split_point sign dot integer, fraction skip_sign() def convert_integer(s): n = 10*n + decimal(e) convert_ints atoi/atof int/float