properties数据处理

1、介绍

1.1 数据结构

properties数据指的是一组或多组键值对数据结构,list[list[str, str]]。

二维数组结构,其中一维的元素是长度为2的list,二维的元素是str类型,分别表示键和值。

1.2 场景

在诸多业务场景中,存在使用properties数据的需求。

  • 配置文件
  • 请求和响应头部
  • url的直接参数
  • 请求体部
  • cookies

1.3 函数和类

为了方便处理properties数据,定义相关的函数和类。之所以不直接使用list或dict进行处理,大概以下几点:

  • dict要求键是不可重复的,会自动去重。但是类似响应头部set-cookie字段是需要允许键重复的
  • list的copy是浅复制,但需求一般是深复制。所以需要定义函数和方法
  • dict和list都不强调元素是str类型,而properties函数和类都强调键和值都为str类型
  • 编写函数和类,能够显著的节俭代码,进行复用

2、PropertiesModule

定义了相关的函数

2.1 parse

parse(s, sep1, sep2, strip_flag=False)->list[list[str, str]]
  • 解析字符串为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • s,str类型,待解析字符串
  • sep1,str类型,键值对和键值对之间的分隔符
  • sep2,str类型,键和值之间的分隔符
  • strip_flag,bool类型,为True表示会对键和值进行去除首尾空白字符,即调用.strip()方法
  • 如果s、sep1、sep2任一者为空字符串,则直接返回空list []

2.2 toString

toString(arr, sep1, sep2)->str
  • 将properties数据结构,组装为str类型返回。如果arr长度为0,返回空字符串''
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • sep1,str类型,键值对和键值对之间的分隔符
  • sep2,str类型,键和值之间的分隔符

 2.3 clone

clone(arr) -> list[list[str, str]]
  • 深克隆,即克隆二维的str字面值。而非浅克隆只克隆一维的地址
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list

2.4 hasName

hasName(arr, name, ignore_case) -> bool
  • 判断properties数据结构中是否包含某键,包含则返回bool类型的True
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • name,str类型,待匹配键名称
  • ignore_case,bool类型,是否忽略大小写进行匹配。如果为True,会将各键转小写,以及name转小写进行匹配

2.5 getFirstValue

getFirstValue(arr, name, ignore_case, default=None) -> str/None
  • 获取首个键匹配所对应的值,如果没有匹配,则返回default
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • name,str类型,待匹配键名称
  • ignore_case,bool类型,是否忽略大小写进行匹配。如果为True,会将各键转小写,以及name转小写进行匹配
  •  default,默认值为None,即没有任何匹配时所返回。使用时可以考虑根据需求设置为空字符串''或其它字符串

2.6 getValue

getValue(arr, name, ignore_case) -> list[str]
  • 获取键所匹配的所有值,返回类型list[str]。主要是针对响应头部set-cookie这类允许重复的键
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • name,str类型,待匹配键名称
  • ignore_case,bool类型,是否忽略大小写进行匹配。如果为True,会将各键转小写,以及name转小写进行匹配

2.7 remove

remove(arr, name, ignore_case)
  • 移除所有键所匹配的项
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • name,str类型,待匹配键名称
  • ignore_case,bool类型,是否忽略大小写进行匹配。如果为True,会将各键转小写,以及name转小写进行匹配
  • 需要注意,这里移除的算法需要考虑移除某项后对其它项的索引影响
    • 思路一,是使用while,索引递增判断,如果执行移除,则不+1再次判断。反之不移除则+1
    • 思路二,准备新的存储对象,索引递增判断,如果需要移除则不添加到新存储对象,反之则添加

2.8 update

update(arr: list, name: str, value: str, ignore_case: bool):
  • 更新所有键所匹配的项
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • name,str类型,待匹配键名称
  • value,str类型,更新的值
  • ignore_case,bool类型,是否忽略大小写进行匹配。如果为True,会将各键转小写,以及name转小写进行匹配

2.9 add

add(arr: list, name: str, value: str):
  • 添加一组键值对
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list
  • name,str类型,键名称
  • value,str类型,值

2.10 getNames

getNames(arr) -> list[str]
  • 获取所有的键,返回类型list[str]
  • arr,为properties数据结构,即二维list,其中一维的元素是长度为2、元素为str的list

3、代码

PropertiesModule.py

"""
解析函数,将字符串s解析为properties结构,比如'a=1&b=2'解析为[['a','1'],['b','2']]
@s      待解析文本
@sep1   属性值对与属性值对之间的间隔
@sep2   属性值对内部,名称和值的间隔
@strip_flag  是否对解析后的名称和值,去除前后的空白符
"""


def parse(s: str, sep1: str, sep2: str, strip_flag: bool = False):
    """parse(s, sep1, sep2, strip_flag=False)->list[list[str, str]]"""
    # 返回对象
    result = []
    # 如果存在空字符串,直接结束
    if s == '' or sep1 == '' or sep2 == '':
        return result
    items = s.split(sep1)
    for i in range(len(items)):
        if sep2 in items[i]:
            split = items[i].split(sep2, maxsplit=1)
            if strip_flag:
                split[0], split[1] = split[0].strip(), split[1].strip()
            result.append([split[0], split[1]])
    return result


"""
拼接字符串 比如[['a','1'],['b','2']]拼接为'a=1&b=2'
@arr: 属性值对列表
@sep1   属性值对与属性值对之间的间隔
@sep2   属性值对内部,名称和值的间隔
"""


def toString(arr: list, sep1: str, sep2: str):
    """toString(arr, sep1, sep2)->str"""
    result = ''
    if len(arr) > 0:
        result = arr[0][0] + sep2 + arr[0][1]
    for i in range(1, len(arr)):
        result = result + sep1 + arr[i][0] + sep2 + arr[i][1]
    return result


"""
克隆属性值对,深层克隆,克隆值
@arr: 属性值对列表
"""


def clone(arr: list):
    """clone(arr) -> list[list[str, str]]"""
    # list的copy是浅克隆,但是这里list的元素都是list,所以不能直接用
    result = []
    for i in range(len(arr)):
        result.append([arr[i][0], arr[i][1]])
    return result


"""
匹配属性值对的名称,如果存在匹配则返回True,否则返回False
@arr: 属性值对列表
@name: 属性名称
@ignoreCase 忽视大小写匹配
"""


def hasName(arr: list, name: str, ignore_case: bool):
    """hasName(arr, name, ignore_case) -> bool"""
    for item in arr:
        if item[0] == name or (ignore_case and item[0].lower() == name.lower()):
            return True
    return False


"""
匹配属性值对的名称,返回第一次匹配项的值
@arr: 属性值对列表
@name: 属性名称
@ignoreCase 忽视大小写
@return 如果匹配则返回值,没有匹配项则返回default,默认是None
"""


def getFirstValue(arr: list, name: str, ignore_case: bool, default=None):
    """getFirstValue(arr, name, ignore_case, default=None) -> str/None"""
    for item in arr:
        if item[0] == name or (ignore_case and item[0].lower() == name.lower()):
            return item[1]
    return default


"""
匹配属性值对的名称,返回所有匹配项的值
@arr: 属性值对列表
@name: 属性名称
@ignoreCase 忽视大小写
"""


def getValue(arr: list, name: str, ignore_case: bool):
    """getValue(arr, name, ignore_case) -> list[str]"""
    result = list()
    for item in arr:
        if item[0] == name or (ignore_case and item[0].lower() == name.lower()):
            result.append(item[1])
    return result


"""
移除
@arr: 属性值对列表
@name: 属性名称
@ignoreCase 忽视大小写
@return 直接在arr对象上操作,无返回
"""


def remove(arr: list, name: str, ignore_case: bool):
    """remove(arr, name, ignore_case)"""
    i = 0
    while i < len(arr):
        if arr[i][0] == name or (ignore_case and arr[i][0].lower() == name.lower()):
            del arr[i]
            # continue很重要,匹配移除当前索引的元素,然后再判断当前索引
            continue
        i = i + 1


"""
更新
@arr: 属性值对列表
@name: 属性名称
@value: 属性值
@ignoreCase 忽视大小写
@return 直接在arr对象上操作,无返回
"""


def update(arr: list, name: str, value: str, ignore_case: bool):
    for item in arr:
        if item[0] == name or (ignore_case and item[0].lower() == name.lower()):
            item[1] = value


"""
追加
@arr: 属性值对列表
@name: 属性名称
@value: 属性值
@return 直接在arr对象上操作,无返回
"""


def add(arr: list, name: str, value: str):
    arr.append([name, value])


"""
返回名称列表
@arr: 属性值对列表
@return list类型
"""


def getNames(arr: list):
    """getNames(arr) -> list[str]"""
    result = []
    for i in range(len(arr)):
        result.append(arr[i][0])
    return result

 

posted @ 2023-05-17 04:17  挖洞404  阅读(14)  评论(0编辑  收藏  举报