api/PropertiesModule

发布时间 2023-05-25 15:12:24作者: 挖洞404

1、介绍

property指的是键和值都为字符串str类型的一组数据。properties则是property的容器,可以包含任意多个property。

(1)业务场景

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

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

(2)实现

为了方便处理properties数据,定义list[list[str, str]]结构进行存储和操作。在此基础上,编写函数和类,能够显著的节俭代码,进行复用

  • api/PropertiesModule,定义对list[list[str, str]]数据的操作函数
  • api/PropertiesClasses,定义properties的相关类

之所以不直接使用list或dict进行处理,大概以下几点:

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

2、api/PropertiesModule

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

@return: list[list[str,str]]类型
如果s,sep1,sep2任一值为空字符串,返回[]
如果根据sep1分隔后的项不包含sep2,则该项相当于不存在
"""


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)):
        # 存在sep2则按第一个进行分割,否则相当于不存在
        if sep2 in items[i]:
            split = items[i].split(sep2, maxsplit=1)
            if strip_flag:
                split[0] = split[0].strip()
                split[1] = split[1].strip()
            result.append([split[0], split[1]])
    return result


"""
格式化字符串 比如[['a','1'],['b','2']]拼接为'a=1&b=2'
@arr: list[list[str, str]]类型,任意多组的键值对
@sep1: str类型,属性值对与属性值对之间的间隔
@sep2: str类型,属性值对内名称和值的间隔

@return: str类型
如果arr的长度为0,则返回空字符串''
"""


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: list[list[str, str]]类型,任意多组的键值对

@return: list[list[str,str]]类型
"""


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: list[list[str, str]]类型,任意多组的键值对
@name: str类型,键名
@ignoreCase: bool类型,是否忽视大小写匹配。为True表示忽略

@return: bool类型
"""


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: list[list[str, str]]类型,任意多组的键值对
@name: str类型,键名
@ignoreCase: bool类型,是否忽视大小写匹配。为True表示忽略
@default: 默认值为None,表示如果指定键在arr中不存在时所返回的值。也可以指定为其它值,比如空字符串

@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: list[list[str, str]]类型,任意多组的键值对
@name: str类型,键名
@ignoreCase: bool类型,是否忽视大小写匹配。为True表示忽略

@return: list[str]类型
"""


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: list[list[str, str]]类型,任意多组的键值对
@name: str类型,键名
@ignoreCase: bool类型,是否忽视大小写匹配。为True表示忽略

@return: 直接在对象上操作,无返回
"""


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: list[list[str, str]]类型,任意多组的键值对
@name: str类型,待匹配键名
@value: str类型,待更新的值
@ignoreCase: bool类型,是否忽视大小写匹配。为True表示忽略

@return: 直接在对象上操作,无返回
"""


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: list[list[str, str]]类型,任意多组的键值对
@name: str类型,待追加项的键名
@value: str类型,待追加项的值

@return: 直接在对象上操作,无返回
"""


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


"""
获取键名列表
@arr: list[list[str, str]]类型,任意多组的键值对

@return list[str]类型
"""


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


"""
获取指定索引的项
@arr: list[list[str, str]]类型,任意多组的键值对
@index int类型,指定索引

@return list[str, str]
"""


def get(arr: list, index: int):
    """get(arr, index) -> list[str, str]"""
    return arr[index]


"""
获取指定索引项的键名
@arr: list[list[str, str]]类型,任意多组的键值对
@index int类型,指定索引

@return str类型
"""


def get_name(arr: list, index: int):
    """get(arr, index) -> str"""
    return arr[index][0]


"""
获取指定索引项的值
@arr: list[list[str, str]]类型,任意多组的键值对
@index int类型,指定索引

@return str类型
"""


def get_value(arr: list, index: int):
    """get(arr, index) -> str"""
    return arr[index][1]


"""
基于索引删除某一项元素
@arr: list[list[str, str]]类型,任意多组的键值对
@index: int类型

@return: 直接在对象上操作,无返回
"""


def remove_index(arr: list, index: int):
    del arr[index]



"""
更新指定索引项
@arr: list[list[str, str]]类型,任意多组的键值对
@index: int类型,待匹配的项索引
@name: str类型,待更新的键名
@value: str类型,待更新的值

@return: 直接在对象上操作,无返回
"""


def update_index(arr: list, index: int, name: str, value: str):
    arr[index][0] = name
    arr[index][1] = value