• 数据编码与处理


    一、读写CSV数据

      (1)使用csv库处理CSV数据

    import csv
    with open('./stock.csv') as f:
        f_csv = csv.reader(f)
        headers = next(f_csv)
        for row in f_csv:
            # process row

      由于每一行的row是个列表,访问需要用row[0]、row[1],

      (2)可以考虑转换成命名元组访问。

    import csv
    from collections import namedtuple
    
    with open('./stock.csv') as f:
        f_csv = csv.reader(f)
        headers = next(f_csv)
        Row = namedtuple('Row',headers)
        for r in f_csv:
            row = Row(*r)
            # process row

      (3)转换为字典

    import csv
    with open('./stock.csv') as f:
        f_csv = csv.DictReader(f)
        for row in f_csv:
            # process row

      写入CSV数据:

    import csv
    headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume']
    rows = [
        ('AA', '39.48', '6/11/2007', '9:34am', '-0.18', '428900'),
        ('BB', '48.54', '8/25/2001', '19:57am', '-0.44', '142800'),
        ('CC', '92.13', '3/18/1886', '3:11am', '-0.67', '126700'),
        ('DD', '79.25', '2/05/1999', '8:22am', '-0.27', '110000'),
    ]
    
    with open('stock2.csv','w') as f:
        f_csv = csv.writer(f)
        f_csv.writerow(headers)
        f_csv.writerows(rows)

      如果数据是字典序列,那么可以这样处理:

    import csv
    headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume']
    rows = [
        {'Symbol':'AA','Price':39.48,'Date':'6/11/2007', 'Time':'9:34am', 'Change':-0.18, 'Volume':428900}
    ]
    
    with open('stock2.csv','w') as f:
        f_csv = csv.DictWriter(f, headers)
        f_csv.writeheader()
        f_csv.writerows(rows)

      标题行出现非法字符,需要进行转换。

    import re
    with open('./stock.csv') as f:
        f_csv = csv.reader(f)
        headers = [ re.sub('[^a-zA-Z_]', '_', h) for h in next(f_csv)]

      读取数据时,将部分数据转换成除字符串之外的类型。

    import csv,re
    
    col_type = [str,float,str,str,float,str]
    with open('./stock.csv') as f:
        f_csv = csv.reader(f)
        headers = [ re.sub('[^a-zA-Z_]', '_', h) for h in next(f_csv)]
    for row in f_csv: row = tuple( convert(value)for convert, value in zip(col_type, row) )

      字段转化成字典:

    field_type = [
        ('Price',float),
        ('Change',float),
        ('Volume',int),
    ]
    
    with open('./stock.csv') as f:
        for row in csv.DictReader(f):
            row.update( (key,convert(row[key])) for key, convert in field_type)
            print(row)

    二、读写JSON数据

      (1)字符串形式:json.dumps()、json.loads()

      (2)文件形式:json.dump()、json.load()

      (3)使用pprint()函数,合理格式输出 或者 在json.dumps()函数中使用indext参数

      >>> from urllib.request import urlopen

      >>> pprint(json_resp)

      >>> print(json.dumps(data, indent=4))

      (4)load时解码为OrderDict有序字典

      >>> from collections import OrderedDict

      >>> data = json.loads(s, object_pairs_hook=OrderedDict)

      (5)JSON字典转变为Python对象

    class JSONObject:
        def __init__(self,d):
            self.__dict__ = d
    
    >>> data = json.loads(s, object_hook=JSONObject)
    >>> data.name

      (6)序列化类实例,提供一个函数作为输入并返回一个可以被序列化处理的字典。

    def serialize_instance(obj):
        obj = { '__classname__' : type(obj).__name__ }
        obj.update(vars(obj))
        return obj
    
    class Point:
        def __init__(self,x,y):
            self.x = x
            self.y = y
    
    classes = {
        'Point':Point
    }
    
    def unserialize_instance(d):
    
        clsname = d.pop('__classname__',None)
        if clsname:
            cls = classes[clsname]
            obj = cls.__new__(cls)
            for key,value in d.items():
                setattr(obj,key,value)
                return obj
        return d
    
    >>> p = Point(2, 3)
    >>> s = json.dumps(p, default  = serialize_instance)
    >>> a = json.loads(s, object_hook = unserialize_instance )

    三、解析简单的XML文档

      xml.etree.ElementTree.parse()函数将整个XML文档解析为一个文档对象。

      之后,就可以利用find()、iterfind()、findtext()方法查询特定的XML元素。

      (1)指定标签时,需要整体考虑文档的结构。每一个查找操作都是相对于一个起始元素来展开的。

      (2)doc.iterfind('channel/item')的调用会查找所有在channel元素之下的item元素。doc代表着文档的顶层。

      (3)之后对item.findtext()的调用就相对于已找到的item元素来展开。

      (4)每个由ElementTree模块所表示的单个元素都有重要的属性和方法,tag属性包含标签的名称,text属性包含附着的文本,get()方法可以用来提取出属性。

    四、以增量的方式解析大型XML文件

      从大型XML文档中提取出数据时,使用迭起器和生成器。

    <?xml version="1.0" encoding="ISO-8859-1"?>
    
    <!-- Edited with XML Spy v2007 (http://www.altova.com) -->
    
    <breakfast_menu>
    <food>
        <food>
    
            <name>Belgian Waffles</name>
    
            <price>$5.95</price>
    
            <description>two of our famous Belgian Waffles with plenty of real maple syrup</description>
    
            <calories>650</calories>
    
        </food>
    
        <food>
    
            <name>Strawberry Belgian Waffles</name>
    
            <price>$7.95</price>
    
            <description>light Belgian waffles covered with strawberries and whipped cream</description>
    
            <calories>900</calories>
    
        </food>
    
        <food>
    
            <name>Berry-Berry Belgian Waffles</name>
    
            <price>$8.95</price>
    
            <description>light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
    
            <calories>900</calories>
    
        </food>
    
        <food>
    
            <name>French Toast</name>
    
            <price>$4.50</price>
    
            <description>thick slices made from our homemade sourdough bread</description>
    
            <calories>600</calories>
    
        </food>
    
        <food>
    
            <name>Homestyle Breakfast</name>
    
            <price>$6.95</price>
    
            <description>two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
    
            <calories>950</calories>
    
        </food>
    </food>
    </breakfast_menu>
    simple.xml

      iterparse()方法允许我们对XML文档做增量式处理;

      迭代器产生出形式为(event, elem)的元组,event是列出的事件,而elem是对应的XML元素。

    from xml.etree.ElementTree import iterparse
    
    def parse_and_remove(filename, path):
    
        tag_stack = []
        elem_stack = []
        path_parts = path.split('/')
    
        doc = iterparse(filename, ('start', 'end'))
        next(doc)
        for event, elem in doc:
            if event == 'start':
                tag_stack.append(elem.tag)
                elem_stack.append(elem)
            elif event == 'end':
                if tag_stack == path_parts:
                    yield elem
                    elem_stack[-2].remove(elem)
                try:
                    tag_stack.pop()
                    elem_stack.pop()
                except IndexError as e:
                    pass
    
    data = parse_and_remove('./simple.xml','food/food')
    for i in data:
        print('>>>>>>>>>>>>>>>>',i,'<<<<<<<<<<<<<<<')

      elem_stack[-2].remove(elme),这一行代码使得之前通过yield产生的元素从它们的父节点中移除。

      因此可假设其再也没有任何其他的引用存在,因此该元素被销毁进而可以回收它所占用的内存。

    五、将字典转换为XML

      xml.etree.ElementTree库同样可以用来创建XML文档。

    from xml.etree.ElementTree import Element
    def dict_to_xml(tag, d):
        elem = Element(tag)
        for key, val in d.items():
            child = Element(key)
            child.text = str(val)
            elem.append(child)
        return elem
    
    >>> s = { 'name':'GGGG','share':'100','price':'23.44'}
    >>> e = dict_to_xml('stock', s)
    <Element 'stock' at 0x000001CAFEE80F98>

      转换的结果是得到一个Element实例。可以利用xml.etree.ElementTree库中的tostring()函数将其转换为字节串。

    >>> from xml.etree.ElementTree import tostring
    >>> tostring(e)
    b'<stock><name>GGGG</name><price>23.44</price><share>100</share></stock>'

      为元素附加属性,使用set()方式实现。

      如果要考虑元素间的顺序,创建OrderedDict有序字典来取代普通的字典。

      当创建XML时,倾向于只使用字符串来完成:

    def str_to_xml(tag, d):
        parts = ['<{}>'.format(tag)]
        for key, val in d.items():
            parts.append('<{0}>{1}</{0}>'.format(key, val))
        parts.append('</{}>'.format(tag))
        return ''.join(parts)
    
    >>> e = str_to_xml('stock', s)
    <stock><name>GGGG</name><price>23.44</price><share>100</share></stock>

      当字典中包含有特殊字符时:{ 'name' : '<spam>' }

    >>> d = {'name':'<spam>'}
    >>> tostring(dict_to_xml('stock',d))
    b'<stock><name>&lt;spam&gt;</name></stock>'
    >>> str_to_xml('stock',d)
    <stock><name><spam></name></stock>

      需要手工对字符做转义处理,可以使用xml.sax.saxutils中的escape()和unescape()函数。

    >>> from xml.sax.saxutils import escape,unescape
    >>> escape('<spam>')
    '&lt;spam&gt;'
    >>> unescape(_)
    '<spam>'

    六、解析、修改和重写XML

      修改XML文档的结构主要是对父元素进行操作,如果需要移除某个元素,那么就利用它的直接父节点的remove()方法完成。

      如果插入或添加新的元素,使用父节点的insert()和append()方法来完成。这些元素也可以使用索引和切片操作来进行操控,比如element[i]或element[i:j]。

      >>> from xml.etree.ElementTree impor parse,Element

      >>> doc = parse('simple.xml')

      >>> root = doc.getroot()

      >>> root.remove(root.find('sri'))

      >>> root.getchildren().index(root.find('nm'))  # 1

      >>> e = Element('spam')

      >>> e.text = 'This is a test'

      >>> root.insert(2, e)  # 插入在<nm>...</nm> 后面 ..

      >>> doc.write('new_simple.xml', xml_declaration=True)

    七、用命名空间来解析XML文档

      对包含有命名空间的XML文档进行解析会非常繁琐。XMLNamespaces类的功能只是用来稍微简化一下这个过程,

      能够在后续的操作中使用缩短的命名空间名称,而不必去使用完全限定的URI。

    class XMLNamespace:
        
        def __init__(self, **kwargs):
            self.namespace = {}
            for name, uri in kwargs.items():
                self.register(name, uri)
                
        def register(self,name, uri):
            self.namespace[name] = '{'+uri+'}'
        
        def __call__(self, path):
            return path.format_map(self.namespace)
    
    >>> ns = XMLNamespace(html='http://www.w3.org/1999/xhtml')
    >>> doc.find(ns('content/{html}/html/{html}/head/{html}/title'))
    'Hello World'

      正在解析的文本除了命名空间之外的其他高级XML特性,那么最好还是使用lxml库。

    九、编码和解码十六进制数字

      (1)字节流 =》十六进制数组成的字符串

      >>> import binascii

      >>> s = b'hello'

      >>> h = binascii.b2a_hex(s)  b'68656c6c6f'

      (2)十六进制数组成的字符串 =》字节流

      >>> binascii.a2b_hex(h)  b'hello'

      (3)base64模块下,字节流 =》十六进制数组成的字符串

      >>> import base64

      >>> h = base64.bl6encode(s)  b'68656C6C6F'

      (4)base64模块下,十六进制数组成的字符串 =》字节流

      >>> s = base64.bl6decode(h)  b'hello'

      base64.bl64encode和base64.bl64decode只能对大写形式的十六进制数进行操作,而binascii模块能够处理任意一种情况。

      

    十、Base64编码和解码

      采用Base64编码对二进制数据做编码解码操作。

      (1)字节串编码

      >>> import base64

      >>> s = b'hello'

      >>> a = base64.b64encode(s)  b'aGVsbG8'

      (2)解码

      >>> base64.n64decode(a)  b'hello'

  • 相关阅读:
    Tinkoff Challenge
    Uva 12298 超级扑克2
    BZOJ 1031 字符加密
    HDU 4944 逆序数对
    51nod 1215 数组的宽度
    LA 3126 出租车
    LA 3415 保守的老师
    51nod 1275 连续子段的差异
    Uva 11419 我是SAM
    LA 4043 最优匹配
  • 原文地址:https://www.cnblogs.com/5poi/p/11515668.html
Copyright © 2020-2023  润新知