package net.northking.cctp.element.string.keywords;


import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson.JSON;
import net.northking.cctp.element.core.IExecuteContext;
import net.northking.cctp.element.core.annotation.Argument;
import net.northking.cctp.element.core.annotation.Keyword;
import net.northking.cctp.element.core.annotation.Keywords;
import net.northking.cctp.element.core.annotation.Return;
import net.northking.cctp.element.core.type.DataType;
import net.northking.cctp.element.core.type.InputType;
import net.northking.cctp.element.core.type.ParamScope;
import net.northking.cctp.element.string.enums.*;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Keywords
public class StringTools {

    /**
     * <p>比较两个字符串大小，大小写敏感。</p>
     * 返回值 =0，<b>str1</b> = <b>str2</b>
     * <br>
     * 返回值 &lt;0，<b>str1</b> &lt; <b>str2</b>
     * <br>
     * 返回值 &gt;0，<b>str1</b> &gt; <b>str2</b>
     * <br>
     * Example:
     * <pre>
     * compare("abc", "abc", false) = 0
     * compare("a", "b", false)     &lt; 0
     * compare("b", "a", false)     &gt; 0
     * compare("a", "B", false)     &gt; 0
     * compare("ab", "abc", false)  &lt; 0
     * compare("abc", "ABC", true)  = 0
     * compare("a", "B", true)      &lt; 0
     * compare("A", "b", true)      &lt; 0
     * compare("ab", "ABC", true)   &lt; 0
     * </pre>
     *
     * @param str1       字符串
     * @param str2       字符串
     * @param ignoreCase 忽略大小写
     * @return &lt; 0, 0, &gt; 0
     */
    @Keyword(alias = "比较字符串",category = "02")
    @Return(name = "result", comment = "比较结果", type = DataType.INTEGER)
    public int compare(
            @Argument(name = "str1", comment = "字符串", type = DataType.STRING) String str1,
            @Argument(name = "str2", comment = "字符串", type = DataType.STRING) String str2,
            @Argument(name = "ignoreCase", comment = "忽略大小写", type = DataType.BOOLEAN, required = false,
                      defaultValue = "false") boolean ignoreCase,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
            Integer s = ignoreCase ? StringUtils.compareIgnoreCase(str1, str2) : StringUtils.compare(str1, str2);
        save2ContentText(value,executeContext,s);
        return s;
    }

    // ########################################
    // 查询&统计操作
    // ########################################

    /**
     * <p>查找字符序列中的第一个索引，忽略大小写。</p>
     * <pre>
     * indexOf("", "", false)           = 0
     * indexOf("aabaabaa", "a", false)  = 0
     * indexOf("aabaabaa", "b", false)  = 2
     * indexOf("aabaabaa", "ab", false) = 1
     * indexOf("aabaabaa", "", false)   = 0
     * indexOf("aabaabaa", "A", true)   = 0
     * indexOf("aabaabaa", "aB", true)  = 1
     * </pre>
     *
     * @param str        字符串
     * @param searchStr  查找字符串
     * @param ignoreCase 忽略大小写
     * @return 搜索字符序列第一个索引，-1表示没有匹配项
     */
    @Keyword(alias = "索引字符串中字符(字符第一次出现位置)",category = "02")
    @Return(name = "result", comment = "索引下标", type = DataType.INTEGER)
    public int indexOf(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING,required = false) String str,
            @Argument(name = "searchStr", comment = "字符串", type = DataType.STRING,required = false) String searchStr,
            @Argument(name = "ignoreCase", comment = "忽略大小写", type = DataType.BOOLEAN, required = false,
                      defaultValue = "false") boolean ignoreCase,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
            Integer s = ignoreCase ? StringUtils.indexOfIgnoreCase(str, searchStr) : StringUtils.indexOf(str, searchStr);
        save2ContentText(value,executeContext,s);
        return s;
    }

    /**
     * <p>判断字符串是否为空</p>
     * Example:
     * <pre>
     * isEmpty("")        = true
     * isEmpty(" ")       = false
     * isEmpty("bob")     = false
     * isEmpty("  bob  ") = false
     * </pre>
     *
     * @param str 字符串
     * @return true/false
     */
    @Keyword(alias = "字符串为Empty",category = "02")
    @Return(name = "empty", comment = "字符串为空", type = DataType.BOOLEAN)
    public boolean isEmpty(@Argument(name = "str", comment = "字符串", type = DataType.STRING,
                                     notNull = false,required = false) String str,
                           @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
                           IExecuteContext executeContext) {
            Boolean s =  StringUtils.isEmpty(str);
        save2ContentText(value,executeContext,s);
        return s;
    }

    /**
     * <p>检查字符串是否包含查找字符串、检查查找字符串是否是字符串前缀、检查查找字符串是否是字符串后缀。</p>
     * <pre>
     * contains("tes1","es",null,null,true,"0")      = true
     * contains("tes1","1es",null,null,true,"0")     = false
     * contains("tes1",null,"t",null,true,"1")       = true
     * contains("tes1",null,"e",null,true,"1")       = false
     * contains("tes1",null,null,"1",true,"2")       = true
     * contains("tes1",null,null,"0",true,"2")       = false
     * </pre>
     *
     * @param str        字符串
     * @param searchStr  查找字符串
     * @param prefix        前缀
     * @param suffix  后缀
     * @param ignoreCase 忽略大小写
     * @param type 类型("0"-是否包含，”1“-是否前缀,"2"-是否后缀)
     * @return true/false
     */
    @Keyword(alias = "字符串包含字符",category = "02")
    @Return(name = "contains", comment = "字符串包含", type = DataType.BOOLEAN)
    public boolean contains(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String str,
            @Argument(name = "searchStr", comment = "字符串", type = DataType.STRING,required = false) String searchStr,
            @Argument(name = "prefix", comment = "前缀", type = DataType.STRING,required = false) String prefix,
            @Argument(name = "suffix", comment = "后缀", type = DataType.STRING,required = false) String suffix,
            @Argument(name = "ignoreCase", comment = "忽略大小写", type = DataType.BOOLEAN, required = false,
                      defaultValue = "false") boolean ignoreCase,
            @Argument(name = "type", comment = "类型", type = DataType.ENUM,enumValues = TypeConversionContainEnum.class,inputType = InputType.select) String type,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
        TypeConversionContainEnum typeConversionEnum = TypeConversionContainEnum.from(type);
        Boolean s =null;
            switch (typeConversionEnum) {
                case isContain:
                    s = ignoreCase ? StringUtils.containsIgnoreCase(str, searchStr) : StringUtils.contains(str, searchStr);
                    break;
                case isPrefix:
                    s = ignoreCase ? StringUtils.startsWithIgnoreCase(str, prefix) : StringUtils.startsWith(str, prefix);
                    break;
                case isSuffix:
                    s = ignoreCase ? StringUtils.endsWithIgnoreCase(str, suffix) : StringUtils.endsWith(str, suffix);
                    break;
            }
            save2ContentText(value,executeContext,s);
            return s;
    }

    /**
     * <p>计算子字符串在较大字符串中出现的次数。</p>
     * Example:
     * <pre>
     * countMatches("abba", "")    = 0
     * countMatches("abba", "a")   = 2
     * countMatches("abba", "ab")  = 1
     * countMatches("abba", "xxx") = 0
     * </pre>
     *
     * @param str      字符串
     * @param countStr 统计字符串
     * @return 字符串
     */
    @Keyword(alias = "计算字符出现次数",category = "02")
    @Return(name = "result", comment = "出现次数", type = DataType.INTEGER)
    public int countMatches(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String str,
            @Argument(name = "countStr", comment = "统计字符串", type = DataType.STRING,required = false) String countStr,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {

            Integer s = StringUtils.countMatches(str, countStr);
            save2ContentText(value,executeContext,s);
            return s;
    }

    // ########################################
    // 提取操作
    // ########################################

    /**
     * <p>截取字符串</p>
     * Example:
     * <pre>
     * substring("tes1","0",0,2,null,null,null)   = "te"
     * substring("tes1","1",0,0,"e",null,null)   = "s1"
     * substring("tes1","2",0,0,"e",null,null)   = "t"
     * substring("tes1","3",0,0,null,"t","s")   = "e"
     * substring("tes1es1","4",0,0,"es",null,null)   = "1"
     * substring("tes1es1","5",0,0,"es",null,null) = "tes1"
     * </pre>
     *
     * @param str   字符串
     * @param type 类型("0"-根据起始结束坐标截取字符串;"1"-截取分割字符串第一次出现位置后的部分;
     *             "2"-截取分割字符串第一次出现位置前的部分;"3"-截取开始位置字符串与结束位置字符串之间的部分;
     *             "4"-截取分割字符串最后一次出现位置后的部分;"5"-截取分割字符串最后一次出现位置前的部分)
     * @param start   开始下标
     * @param end   结束下标
     * @param separator 分割字符
     * @param open   开始位置字符串
     * @param close   结束位置字符串
     * @return 新的字符串
     */
    @Keyword(alias = "截取字符串",category = "02")
    @Return(name = "str", comment = "字符串", type = DataType.STRING)
    public String substring(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String str,
            @Argument(name = "type", comment = "类型", type = DataType.ENUM,enumValues = TypeConversionSubStringEnum.class,inputType = InputType.select) String type,
            @Argument(name = "start", comment = "开始下标", type = DataType.INTEGER) int start,
            @Argument(name = "end", comment = "结束下标", type = DataType.INTEGER) int end,
            @Argument(name = "separator", comment = "分割字符", type = DataType.STRING) String separator,
            @Argument(name = "open", comment = "开始位置字符串", type = DataType.STRING) String open,
            @Argument(name = "close", comment = "结束位置字符串", type = DataType.STRING) String close,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
        TypeConversionSubStringEnum typeConversionEnum = TypeConversionSubStringEnum.from(type);
            String s =null;
        switch (typeConversionEnum) {
            case substringBySE:
                s = StringUtils.substring(str, start, end);
                break;
            case substringAfter:
                s = StringUtils.substringAfter(str, separator);
                break;
            case substringBefore:
                s = StringUtils.substringBefore(str, separator);
                break;
            case substringBetween:
                s = StringUtils.substringBetween(str, open, close);
                break;
            case substringAfterLast:
                s = StringUtils.substringAfterLast(str, separator);
                break;
            case substringBeforeLast:
                s = StringUtils.substringBeforeLast(str, separator);
                break;
        }
            save2ContentText(value,executeContext,s);
            return s;
    }

    /**
     * <p>通过正则表达式提取源文本中匹配的某组数据。</p>
     * Example:
     * <pre>
     * extractRegMatchText("A-1-B-2$A-11-B-22$", "A-(.*?)-B-(.*?)\$", 0, 1)    = ”A-1-B-2$“
     * extractRegMatchText("A-1-B-2$A-11-B-22$", "A-(.*?)-B-(.*?)\$", 0, 2)    = ”A-11-B-22$“
     * extractRegMatchText("A-1-B-2$A-11-B-22$", "\d+", 0, 2)                  = 2
     * </pre>
     *
     * @param text    源文本字符串
     * @param reg     正则表达式，一对括弧"()"表示一组
     * @param groupNo 组索引0表示在整个字符串中根据正则表达式匹配,1表示在第一个大括号'()',2表示在第二个'()'
     * @param num     0表示随机返回一个匹配文本，n(正整数)表示返回第n个匹配文本,n>匹配到的字符集的长度，取最后一个字符
     * @return 返回匹配数据文本
     */
    @Keyword(alias = "正则表达式提取数据",category = "02")
    @Return(name = "result", comment = "匹配数据文本", type = DataType.STRING)
    public static String extractRegMatchText(
            @Argument(name = "text", comment = "源数据文本", type = DataType.STRING) String text,
            @Argument(name = "reg", comment = "正则表达式", type = DataType.STRING) String reg,
            @Argument(name = "groupNo", comment = "组索引", type = DataType.INTEGER, required = false,
                      defaultValue = "1") int groupNo,
            @Argument(name = "num", comment = "匹配数", type = DataType.INTEGER, required = false,
                      defaultValue = "1") int num,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
        if (num < 0) {
            throw new IllegalArgumentException("匹配数不能为负数");
        }
        List<String> result = extractRegMatchTexts(text, reg, groupNo);
        int total = result.size();
        if (total == 0) {
            save2ContentText(value,executeContext,"");
            return "";
        }
        if (num == 0) {
            int index = RandomUtils.nextInt(0, total);
            save2ContentText(value,executeContext,result.get(index));
            return result.get(index);
        } else {
            save2ContentText(value,executeContext,result.get(num > total ? total - 1 : num - 1));
            return result.get(num > total ? total - 1 : num - 1);
        }
    }

    /**
     * <p>通过正则表达式提取源文本中所有匹配的数据。</p>
     * Example:
     * <pre>
     * extractRegMatchTexts("A-1-B-2$A-11-B-22$", "A-(.*?)-B-(.*?)\\$", 1)      = ["1","11"]
     * extractRegMatchTexts("A-1-B-2$A-11-B-22$", "A-(.*?)-B-(.*?)\\$", 2)      = ["2","22"]
     * extractRegMatchTexts("A-1-B-2$A-11-B-22$", "\\d+", 0)                    = ["1","2","11","22"]
     * </pre>
     *
     * @param text    源文本字符串
     * @param reg     正则表达式，一对括弧"()"表示一组
     * @param groupNo 组索引
     * @return 返回匹配数据List集合
     */
    public static List<String> extractRegMatchTexts(
            @Argument(name = "text", comment = "源数据文本", type = DataType.STRING) String text,
            @Argument(name = "reg", comment = "正则表达式", type = DataType.STRING) String reg,
            @Argument(name = "groupNo", comment = "组索引", type = DataType.INTEGER, required = false,
                      defaultValue = "0") int groupNo) {
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(text);
        List<String> result = new ArrayList<>();
        while (matcher.find()) {
            int groupCount = matcher.groupCount();
            if (groupNo <= groupCount) {
                result.add(matcher.group(groupNo));
            }
        }
        return result;
    }

    // ########################################
    // 分割&拼接操作
    // ########################################

    /**
     * <p>通过指定分隔符，将提供的文本拆分为List集合元素。</p>
     * <i>注意</i>：分隔符不包含在返回的List集合中，相邻的分隔符被视为一个分隔符。
     * <br>
     * Example:
     * <pre>
     * split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
     * split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
     * </pre>
     *
     * @param str       字符串
     * @param separator 分割字符
     * @param max       分割后元素个数
     * @return List集合
     */
    @Keyword(alias = "分割字符串",category = "02")
    @Return(name = "list", comment = "字符串集合", type = DataType.LIST)
    public List split(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String str,
            @Argument(name = "separator", comment = "分割字符", type = DataType.STRING, defaultValue = " ") String separator,
            @Argument(name = "max", comment = "分割后元素个数", type = DataType.INTEGER, defaultValue = "-1" ) Integer max,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
            List s = Arrays.asList(StringUtils.split(str, separator, max));
            save2ContentText(value,executeContext, JSON.toJSON(s));
            return s;
    }

    /**
     * <p>使用指定连接符将List集合中元素连接成字符串。</p>
     * Example:
     * <pre>
     * join(["", "a"], ",")         = ",a"
     * join(["a", "b", "c"], "--")  = "a--b--c"
     * join(["a", "b", "c"], "")    = "abc"
     * </pre>
     *
     * @param list      List集合
     * @param separator 连接字符
     * @return 字符串
     */
    @Keyword(alias = "集合元素连接成字符串",category = "02")
    @Return(name = "str", comment = "字符串", type = DataType.STRING)
    public String join(
            @Argument(name = "list", comment = "list集合", type = DataType.LIST) List list,
            @Argument(name = "separator", comment = "连接字符", type = DataType.STRING,
                      required = false) String separator,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
            String s = StringUtils.join(list, separator);
            save2ContentText(value,executeContext,s);
            return s;
    }

    // ########################################
    // 替换操作
    // ########################################

    /**
     * <p>用一个字符串替换另一个字符串，可设置最大替换次数。</p>
     * Example:
     * <pre>
     * replace("tes1es1", "0","e","E",0)   = "tEs1Es1"
     * replace("tes1es1", "1","e","E",0)   = "tes1es1"
     * replace("tes1es1", "1","e","E",1)   = "tEs1es1"
     * </pre>
     *
     * @param text         字符串
     * @param type 类型("0"-不设置最大替换次数，”1“-设置最大替换次数)
     * @param searchString 查询字符串
     * @param replacement  替换字符串
     * @param max          最大替换次数
     * @return 新的字符串
     */
    @Keyword(alias = "替换字符串",category = "02")
    @Return(name = "str", comment = "字符串", type = DataType.STRING)
    public String replace(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String text,
            @Argument(name = "type", comment = "类型", type = DataType.ENUM,enumValues = TypeConversionReplaceEnum.class,inputType = InputType.select) String type,
            @Argument(name = "searchString", comment = "查询字符串", type = DataType.STRING) String searchString,
            @Argument(name = "replacement", comment = "替换字符串", type = DataType.STRING) String replacement,
            @Argument(name = "max", comment = "最大替换次数", type = DataType.INTEGER, defaultValue = "-1") Integer max,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
        TypeConversionReplaceEnum typeConversionEnum = TypeConversionReplaceEnum.from(type);
            String s =null;
            switch (typeConversionEnum) {
                case replaceByValue:
                    s = StringUtils.replace(text, searchString, replacement);
                    break;
                case replaceByTimes:
                    s = StringUtils.replace(text, searchString, replacement, max);
                    break;
            }
            save2ContentText(value,executeContext,s);
            return s;
    }

    /**
     * <p>字符串脱敏。</p>
     * Example:
     * <pre>
     * hideSensitive("13866668888", 3, 7)   = "138****8888"
     * hideSensitive("13866668888", 7, 3)   = "13866668888"
     * </pre>
     *
     * @param str   字符串
     * @param start 起始下标
     * @param end   结束下标
     * @return 新的字符串
     */
    @Keyword(alias = "字符串脱敏",category = "02")
    @Return(name = "str", comment = "字符串", type = DataType.STRING)
    public String hideSensitive(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String str,
            @Argument(name = "start", comment = "起始下标", type = DataType.INTEGER) int start,
            @Argument(name = "end", comment = "结束下标", type = DataType.INTEGER) int end,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
        if (start < 0) {
            start = 0;
        }
        int length = str.length();
        if (end > length - 1) {
            end = length;
        }
        StringBuilder sb = new StringBuilder(str);
        for (int i = start; i < end; i++) {
            sb.setCharAt(i, '*');
        }
        save2ContentText(value,executeContext,sb);
        return sb.toString();
    }


    /**
     * <p>处理字符串</p>
     * Example:
     * <pre>
     * processString("tes1es1", "0",0, null)      = "Tes1es1"
     * processString("Tes1es1", "1",0, null)    = "tes1es1"
     * processString("TES1ES1", "2",0, null)   = "tes1es1"
     * processString("tes1es1", "3",0, null)  = "TES1ES1"
     * </pre>
     *
     * @param str 字符串
     * @param type 类型("0"-首字母大写;"1"-首字母小写;"2"-字符串转小写;
     *             "3"-字符串转大写)
     * @return 字符串
     */
    @Keyword(alias = "字符串处理",category = "02")
    @Return(name = "str", comment = "字符串", type = DataType.STRING)
    public String processString(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String str,
            @Argument(name = "type", comment = "类型", type = DataType.ENUM,enumValues = TypeConversionProcessEnum.class,inputType = InputType.select) String type,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
        TypeConversionProcessEnum typeConversionEnum = TypeConversionProcessEnum.from(type);
        String s=null;
        switch (typeConversionEnum) {
            case capitalize: {
                s = StringUtils.capitalize(str);
                break;
            }
            case uncapitalize: {
                s = StringUtils.uncapitalize(str);
                break;
            }
            case lowerCase: {
                s = StringUtils.lowerCase(str);
                break;
            }
            case upperCase: {
                s = StringUtils.upperCase(str);
                break;
            }
        }
        save2ContentText(value, executeContext, s);
        return s;
    }
    /**
     * <p>字符串填充</p>
     * Example:
     * <pre>
     * padString("tes1es1", "0",10, "a")   = "aaates1es1"
     * padString("tes1es1", "1",10, "a")   = "tes1es1aaa"
     * </pre>
     *
     * @param str 字符串
     * @param type 类型("0"-左填充;"1"-右填充)
     * @param size 填充后字符串长度
     * @param padStr 填充字符串
     * @return 字符串
     */
    @Keyword(alias = "字符串填充",category = "02")
    @Return(name = "str", comment = "字符串", type = DataType.STRING)
    public String padString(
            @Argument(name = "str", comment = "字符串", type = DataType.STRING) String str,
            @Argument(name = "type", comment = "类型", type = DataType.ENUM,enumValues = TypeConversionPadEnum.class,inputType = InputType.select) String type,
            @Argument(name = "size", comment = "填充后字符串长度", type = DataType.INTEGER) int size,
            @Argument(name = "padStr", comment = "填充字符串", type = DataType.STRING) String padStr,
            @Argument(name = "value", comment = "组件返回值", type = DataType.STRING, scope = ParamScope.OUTPUT, defaultValue = "") String value,
            IExecuteContext executeContext) {
        TypeConversionPadEnum typeConversionEnum = TypeConversionPadEnum.from(type);
        String s=null;
        switch (typeConversionEnum) {
            case leftPad: {
                if (size<0)throw new IllegalArgumentException("填充后字符长度不能为负数");
                s = StringUtils.leftPad(str, size, padStr);
                break;
            }
            case rightPad: {
                if (size<0)throw new IllegalArgumentException("填充后字符长度不能为负数");
                s = StringUtils.rightPad(str, size, padStr);
                break;
            }
        }
        save2ContentText(value, executeContext, s);
        return s;
    }

    public static void save2ContentText(String value, IExecuteContext executeContext, Object s){
        //将值塞入到组件返回值中
        if (value.contains("#{") && value.contains("}")){
            String keyValue = ReUtil.get("(?<=\\#\\{)(.+?)(?=\\})", value, 1);
            // #{} 全局变量
            executeContext.setProjectGlobalVariable(keyValue,s.toString());
        }
        if (value.contains("${") && value.contains("}")){
            String keyValue = ReUtil.get("(?<=\\$\\{)(.+?)(?=\\})", value, 1);
            // ${} 全局变量
            executeContext.setVariable(keyValue, s.toString());
        }
    }
    // ....
}