首页 > 其他 > 详细

按规则解析字符串中的嵌套函数并实现函数调用

时间:2021-06-04 14:22:33      阅读:15      评论:0      收藏:0      [点我收藏+]
按规则解析字符串中的嵌套函数并实现函数调用

需求

1、按照一定规则解析字符串中的函数表达式,并替换这些表达式。这些函数表达式可能包含其它函数表达式,即支持函数嵌套

2、函数表达式格式:${ ?__函数名称() ?}、${__函数名称( 函数参数 )}

注意:

  1. 函数名称以_打头
  2. 函数参数之间使用 || 分隔 形如 ${ __function1( "str_value" || 123456 || ‘test‘ )}
  3. ${ ?之间不能有空格
  4. 函数名称和函数的左括号 ( 之间不能有空隔
  5. 函数支持嵌套,形如:${ __function1( ${__function2()} )}
  6. 函数参数如果是字符串,需要使用单引号、双引号引用 形如 ${ __function1( "str_value" || ?123)} ,${ __function1(key="arg_value")},${ __function1(key=\‘arg_value\‘)},
  7. 字符串替换规则:待替换的字符串,仅包含一个函数表达式,不含其它字符,则该字符串被替换为函数返回值,如果还包含其它字符,或者包含多个函数,则该字符串替换函数表达式之前,会先转换函数返回值为字符串,然后替换这些函数表达式为转换后的函数返回值
  8. 函数参数支持python原生函数 形如 ?${ __function1( set([1,2,3]) )}

解决思路

1、先解析内部函数,再解析其父函数,即从内到外解析

实现方式:查找不包含嵌套函数表达式的函数表达式,先临时替换为“临时插件函数表达式” 形如 ‘@plugin_func_custom_function_name@‘,同时以该值为字典key,存储对应临时函数表达式,然后再用替换后的字符串去查找不包含嵌套函数表达式的函数表达式,然后再替换字符串,直到找不到为止

2、解析替换后的字符串,获取“临时插件函数表达式”,然后执行调用该函数

3、函数参数类型分析

字符串参数要求用 单、双引号 引用,通过eval(参数)转换,如果转换成功则用转换后的,否则用转换前的

实现代码

#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
#

import?re


#?插件函数样例
def?base64(*args,?**kwargs):
????print(‘base64?called‘)
????print(‘args:‘,?args)
????print(‘kwargs:‘,?kwargs)
????return?1


def?read_file(*args,?**kwargs):
????print(‘fread_file?called‘)
????print(‘args:‘,?args)
????print(‘kwargs:‘,?kwargs)
????return?[‘a‘,?1]

def?generate_num(*args,?**kwargs):
????print(‘generate_num?called‘)
????print(‘args:‘,?args)
????print(‘kwargs:‘,?kwargs)
????return?899999



PUGIN_FUNC_MAP?=?{‘read_file‘:read_file,?‘base64‘:base64,?‘generate_num‘:generate_num}?#?存放插件函数名称和对应函数实体的映射

func_map?=?{}?#?存放程序执行过程中,获取的临时函数名称和函数表达式的映射关系

REG_FOR_TEMP_PLUGIN_FUNC?=?re.compile(‘@(plugin_func.+?)@‘,?re.DOTALL)?#?用于查找临时插件函数名称?形如?[‘‘@plugin_func__base64@‘,‘@plugin_func__read_file@‘]
REG_FOR_FUNC_NAME_OF_EXP??=?re.compile(‘\${\s*(_.+?)\(‘,?re.DOTALL)?#?用于查找函数表达式中的函数名称
REG_FOR_FUNC_NAME_AND_ARGS?=?re.compile(‘\${\s*(_.+?)\((.*?)\)\s*}‘,?re.DOTALL)?#?用于查找函数表达式中的函数定义(函数名称及其参数)
REG_FOR_STRICT_FUNC_EXP?=?re.compile(‘\${\s*_.+\(.*?\)\s*}‘,?re.DOTALL)?#?用于获取严格函数定义表达式
REG_FOR_KWARG?=?re.compile(‘^[^"\‘]+[^"\‘]+\s*=\s*.+‘,?re.DOTALL)?#?用于匹配关键词参数

def?_replace_function(string):
????‘‘‘替换字符串中的插件参数‘‘‘


????string?=?string.strip()
????func_name_list?=?REG_FOR_TEMP_PLUGIN_FUNC.findall(string)?#?获取函数名称列表?形如?[‘‘@plugin_func__base64@‘,‘@plugin_func__read_file@‘]
????if?len(func_name_list)?==?1?and?string?==?‘@%s@‘?%?func_name_list[0]:?#?整个字符串就是一个函数表达式,字符串代表的值的类型和函数返回值类型相同,如果函数不存在,返回None
????????if?func_name_list[0]?in?func_map:
????????????return?call_plugin_func(func_map.get(func_name_list[0]))
????else:
????????for?func_name?in?func_name_list:
????????????if?func_name?in?func_map:
????????????????string?=?string.replace(‘@%s@‘?%?func_name,?str(call_plugin_func(func_map.get(func_name))))
????????return?string


def?call_plugin_func(function_express):
????‘‘‘
????调用插件函数
????‘‘‘

????try:
????????result?=?REG_FOR_FUNC_NAME_AND_ARGS.findall(function_express)?#?查找函数表达式中的函数定义(函数名称及其参数)
????????if?result:
????????????plugin_func_name,?plugin_func_args?=?result[0]
????????????plugin_func_name?=?plugin_func_name.strip(‘_‘)?#?去掉函数前缀标识?_?以获取真正的函数

????????????plugin_func_args?=?plugin_func_args.strip()
????????????plugin_func_arg_list?=?[]
????????????if?plugin_func_args:
????????????????plugin_func_arg_list?=?plugin_func_args.split("||")?#?函数参数要求用?||?分隔

????????????position_arg_list?=?[]?#?存放位置参数
????????????keyword_arg_dict?=?{}??#?存放关键词参数

????????????for?item?in?plugin_func_arg_list:
????????????????item?=?item.strip()
????????????????if?REG_FOR_KWARG.findall(item):?#?关键词参数
????????????????????key,?value?=?re.split(‘\s*=[=|\s]*‘,?item)
????????????????????try:
????????????????????????value?=?_replace_function(value)
????????????????????????keyword_arg_dict[key.strip()]?=?eval(value)
????????????????????except?Exception?as?e:
????????????????????????keyword_arg_dict[key.strip()]?=?value
????????????????else:
????????????????????try:
????????????????????????value?=?_replace_function(item)
????????????????????????position_arg_list.append(eval(value))
????????????????????except?Exception?as?e:
????????????????????????position_arg_list.append(value)
????????????if?plugin_func_name?in?PUGIN_FUNC_MAP:
????????????????return?PUGIN_FUNC_MAP.get(plugin_func_name)(*position_arg_list,?**keyword_arg_dict)
????????????else:
????????????????return?None
????????else:?#未找到函数
????????????print(‘没有找到同函数表达式(?%s?)匹配的函数定义‘?%?function_express)
????????????return?None?#
????except?Exception?as?e:
????????raise

def?replace_function(string):
????‘‘‘替换函数‘‘‘

????try:
????????regular_obj?=?re.compile(‘\${\s*(_.+?)\(‘,?re.DOTALL)

????????#?获取临时函数名称
????????temp_func_name_list?=?REG_FOR_FUNC_NAME_OF_EXP.findall(string)
????????string_copy?=?string

????????old_func_name_set?=?set()?#?存放上一次的查找结果
????????while?old_func_name_set?!=?set(temp_func_name_list):
????????????old_func_name_set?=?set(temp_func_name_list)
????????????for?func_name?in?temp_func_name_list:?#?遍历查找函数对应的函数表达式
????????????????pattern?=?‘\${\s*%s\(.*?\)\s*}‘?%?func_name
????????????????func_express_list?=?re.findall(pattern,?string_copy)?#?获取函数表达式(因为可能存在函数嵌套,所以获取的表达式可能是错误的)

????????????????if?not?func_express_list:?#?找不到函数表达式,说明该函数名称无效,不合法
????????????????????continue

????????????????for?func_express?in?func_express_list:
????????????????????temp_func_express?=?func_express.strip().lstrip(‘${‘)
????????????????????if?not?REG_FOR_STRICT_FUNC_EXP.findall(temp_func_express):?#?表达式不包含嵌套函数,则??获取正确的函数表达式进行替换
????????????????????????right_func_express_list?=?REG_FOR_STRICT_FUNC_EXP.findall(func_express)
????????????????????????for?right_func_express?in?right_func_express_list:
????????????????????????????string_copy?=?string_copy.replace(right_func_express,?‘@plugin_func%s@‘?%?func_name)
????????????????????????????func_map[‘plugin_func%s‘?%?func_name]?=?right_func_express?#?建立临时函数名称和函数表达式的映射关系
????????????temp_func_name_list?=?re.findall(regular_obj,?string_copy)

????????if?string_copy?==?string:?#?无变化
????????????return?string
????????return?_replace_function(string_copy)
????except?Exception?as?e:
????????print(‘替换函数出错%s‘?%?e)
????????return?string

#?运行测试
src_string?=?"some?string?${?__base64(?${__read_file(‘filepath‘)}?||?‘string_arg‘?||?‘b==整个表达式(包括b==)是字符串参数‘?||?‘支持单双引号转义字符参数\"?||?‘fake_key_arg1?=?我整个表达式都是字符串参数‘?||?key_arg1=‘关键词字符串参数‘||key_arg2=1?||key_arg3=[1,?2,?3]?||?key_arg4={‘a‘:1,?‘b‘:‘字典参数‘}?)?}?hello"

print(replace_function(src_string))

src_string?=??‘${?__generate_num()?}‘
print(replace_function(src_string))

运行结果如下

按规则解析字符串中的嵌套函数并实现函数调用

原文:https://blog.51cto.com/shouke/2856285

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!