English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
本文では以下のいくつかの面から一つずつ解決策を提供する
1プログラムの主要機能
2実現プロセス
3クラスの定義
4生成器generatorを使用して各オブジェクトを動的に更新し、オブジェクトを返す
5stripを使用して不必要な文字を削除する
6rematchを使用して文字列をマッチングする
7timestrptimeを使用して文字列を時間オブジェクトに変換する
8、完整代码
程序的主要功能
现在有个存储用户信息的像表格一样的文档:第一行是属性,各个属性用逗号(,)分隔,从第二行开始每行是各个属性对应的值,每行代表一个用户。如何实现读入这个文档,每行输出一个用户对象呢?
另外还有4个小要求:
每个文档都很大,如果一次性把所有行生成的那么多对象存成列表返回,内存会崩溃。程序中每次只能存一个行生成的对象。
用逗号隔开的每个字符串,前后可能有双引号(”)或者单引号('),例如”张三“,要把引号去掉;如果是数字,有+000000001.24这样的,要把前面的+和0都去掉,提取出1.24
文档中有时间,形式可能是2013-10-29,也可能是2013/10/29 2:23:56 这样的形式,要把这样的字符串转成时间类型
这样的文档有好多个,每个的属性都不一样,例如这个是用户的信息,那个是通话记录。所以类中的具体属性有哪些要根据文档的第一行动态生成
实现过程
1.类的定义
由于属性是动态添加的,属性-值 对也是动态添加的,类中要含有updateAttributes()和updatePairs()两个成员函数即可,此外用列表attributes存储属性,词典attrilist存储映射。其中init()函数为构造函数。 __attributes前有下划线表示私有变量,不能在外面直接调用。实例化时只需a=UserInfo()即可,无需任何参数。
class UserInfo(object): 'ユーザー情報を復元するクラス' def __init__ (self): self.attrilist={} self.__attributes=[] def updateAttributes(self,attributes): self.__attributes=attributes def updatePairs(self,values): for i in range(len(values)): self.attrilist[self.__attributes[i]]=values[i]
2.用生成器(generator)动态更新每个对象并返回对象
生成器相当于一个只需要初始化一次,就可自动运行多次的函数,每次循环返回一个结果。不过函数用return 返回结果,而生成器用yield 返回结果。每次运行都在yield返回,下一次运行从yield之后开始。例如,我们实现斐波那契数列,分别用函数和生成器实现:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done'
我们计算数列的前6个数:
>>> fib(6) 1 1 2 3 5 8 'done'
如果用生成器的话,只要把 print 改成 yield 就可以了。如下:
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1
使用方法:
>>> f = fib(6) >>> f <generator object fib at 0x104feaaa0> >>> for i in f: ... print(i) ... 1 1 2 3 5 8 >>>
生成器fib自体がオブジェクトであり、yieldに到達すると中断して結果を返し、次回はyieldの次の行から再開します。生成器はgenerator.next()でも実行できます。
私のプログラムでは、生成器部分のコードは以下の通りです:
def ObjectGenerator(maxlinenum): filename='/ホーム/thinkit/ドキュメント/usr_info/USER.csv' attributes=[] linenum=1 a=UserInfo() file=open(filename) while linenum < maxlinenum: values=[] line=str.decode(file.readline(),'gb2312)#linecache.getline(filename, linenum,'gb2312) if line=='': print'reading fail! Please check filename!' break str_list=line.split(',') for item in str_list: item=item.strip() item=item.strip('\"') item=item.strip('\'') item=item.strip('+0*) item=catchTime(item) if linenum==1: attributes.append(item) else: values.append(item) if linenum==1: a.updateAttributes(attributes) else: a.updatePairs(values) yield a.attrilist # 'a' に変更して使用 linenum = linenum +1
その中で、a=UserInfo()はクラスUserInfoのインスタンスです。ドキュメントはgb2312エンコードされた、上記では対応するデコードメソッドを使用しました。最初の行は属性であり、属性リストをUserInfoに格納する関数があります、つまりupdateAttributes();次の行は属性を格納する必要があります。-値を辞書に読み込んで保存します。p.s. Pythonの辞書はマッピング(map)に相当します。
3.stripを使って不必要な文字を除去する方法
上記のコードから、str.strip(somechar)を使うとstr前後のsomechar文字を除去できます。somecharはシンボルまたは正規表現で、上記のように:
item=item.strip()#文字列前後のすべてのエスケープシーケンスを除去します、例えば\t,\nなど item=item.strip('\"')#前後の" item=item.strip('\'') item=item.strip('+0*')#前後の+00...00,*0の個数は任意で、存在しないこともできます
4.re.matchは文字列をマッチングします
関数文法:
re.match(pattern, string, flags=0)
関数引数説明:
引数 説明
pattern マッチングする正規表現
string マッチングする文字列。
flags マッチング方法を制御するフラグ位です。例えば:大文字小文字を区別するか、複数行マッチングなど。
若しくはマッチ成功した場合、re.matchメソッドはマッチオブジェクトを返します。それともNoneを返します。`
>>> s='2015-09-18'
>>> matchObj=re.match(r'\d{4}-\d{2}-\d{2}', s, flags= 0)
>>> print matchObj
<_sre.SRE_Match オブジェクト at 0x7f3525480f38>
1
2
3
4
5
5.time.strptimeを使って文字列を時間オブジェクトに変換する方法
timeモジュールでは、time.strptime(str, format)を使うとstrをformat形式で時間オブジェクトに変換できます。formatの常用フォーマットには:
%y 2桁の年表示(00-99)
%Y 4桁の年表示(000-9999)
%m 月(01-12)
%d 月内の日(0-31)
%H 2424時間制の時間数(0-23)
%I 1224時間制の時間数(01-12)
%M 分数(00=59)
%S 秒(00-59)
さらに、reモジュールを使用して、文字列を正規表現でマッチングし、一般的な時間の形式(YYYY)かどうかを確認する必要があります。/MM/DD H:M:S, YYYY-MM-DD等
上記のコードでは、catchTime関数がitemが時間オブジェクトかどうかを判定し、時間オブジェクトであれば時間オブジェクトに変換します。
以下のコード:
import time import re def catchTime(item): # check if it's time matchObj=re.match(r'\d{4}-\d{2}-\d{2}',item, flags= 0) if matchObj!= None : item =time.strptime(item,'%Y-%m-%d') #print "returned time: %s " %item return item else: matchObj=re.match(r'\d{4}/\d{2}/\d{2}\s\d+:\d+:\d+',item,flags=0 ) if matchObj!= None : item =time.strptime(item,'%Y/%m/%d %H:%M:%S') #print "returned time: %s " %item return item
完全なコード:
import collections import time import re class UserInfo(object): 'ユーザー情報を復元するクラス' def __init__ (self): self.attrilist=collections.OrderedDict()# ordered self.__attributes=[] def updateAttributes(self,attributes): self.__attributes=attributes def updatePairs(self,values): for i in range(len(values)): self.attrilist[self.__attributes[i]]=values[i] def catchTime(item): # check if it's time matchObj=re.match(r'\d{4}-\d{2}-\d{2}',item, flags= 0) if matchObj!= None : item =time.strptime(item,'%Y-%m-%d') #print "returned time: %s " %item return item else: matchObj=re.match(r'\d{4}/\d{2}/\d{2}\s\d+:\d+:\d+',item,flags=0 ) if matchObj!= None : item =time.strptime(item,'%Y/%m/%d %H:%M:%S') #print "returned time: %s " %item return item def ObjectGenerator(maxlinenum): filename='/ホーム/thinkit/ドキュメント/usr_info/USER.csv' attributes=[] linenum=1 a=UserInfo() file=open(filename) while linenum < maxlinenum: values=[] line=str.decode(file.readline(),'gb2312)#linecache.getline(filename, linenum,'gb2312) if line=='': print'reading fail! Please check filename!' break str_list=line.split(',') for item in str_list: item=item.strip() item=item.strip('\"') item=item.strip('\'') item=item.strip('+0*) item=catchTime(item) if linenum==1: attributes.append(item) else: values.append(item) if linenum==1: a.updateAttributes(attributes) else: a.updatePairs(values) yield a.attrilist # 'a' に変更して使用 linenum = linenum +1 if __name__ == '__main__': for n in ObjectGenerator(10): print n # 辞書を出力し、正しいか確認
要約
以上はこの記事の全ての内容であり、皆様の学習や仕事に少しでも役立つことを願っています。何か疑問があれば、コメントを残して交流してください。呐喊教程へのご支援に感謝します。