zoukankan      html  css  js  c++  java
  • Tiny Formater

    昨天看了@Brin想写程序 的文章 几行Java代码实现的简单模板(不是引擎),呵呵,就非常想去掏掏偶滴小兜兜,果然发现一个类似的东西,因为东西太小,没有准备怎么写,但是看到@Brin想写程序的文章,就想着也发篇文章,说一下当时我的想法与思路。
    格式化提供者,用于对字符串进行转换:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public interface FormatProvider {
        /**
         * 把指定的值进行处理后返回
         * 
         * @param string
         *            要进行格式化的值
         * @return 格式化好的值
         * @throws FormatException
         */
        String format(Context context, String string) throws FormatException;

    }




    接口方法只有一个,输入有两个参数,一个是上下文,一个是要进行格式的串,返回的值是格式化处理好的串。
    当然,我也担心,一些串可能会与我们的点位符有冲突,因此期望能由用户自行指定点位符,因此设定了下面的接口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    /**
    * 模式匹配处理接口

    * @author luoguo

    */
    public interface PatternDefine {
        /**
         * 返回正则匹配
         * 
         * @return
         */
        Pattern getPattern();

        /**
         * 设置前缀
         * 
         * @param prefixPatternString
         */
        void setPrefixPatternString(String prefixPatternString);

        /**
         * 设置后缀
         * 
         * @param postfixPatternString
         */
        void setPostfixPatternString(String postfixPatternString);

        /**
         * 设置正则表达式中间部分
         * 
         * @param patternString
         */
        void setPatternString(String patternString);

        /**
         * 返回正文部分
         * 
         * @param string
         * @return
         */
        String getPureMatchText(String string);

        /**
         * 根据正文返回完整部分
         * 
         * @param string
         * @return
         */
        String getFullMatchText(String string);

        /**
         * 设置域分隔符
         * 
         * @return
         */
        void setSplitChar(char splitChar);

        /**
         * 返回分隔符
         * 
         * @return
         */
        char getSplitChar();
    }




    当然上面的接口如果是固定一个的话,框架内部已经提供,不必另行进行扩展。

    格式化接口如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    /**
    * 格式化的接口

    * @author luoguo

    */
    public interface Formater extends FormatProvider {

        /**
         * 设置正则表达式,如果不想用默认正则表达式,可以通过此方法自行定义
         * 
         * @param patternHandle
         */
        void setPatternHandle(PatternDefine patternHandle);

        /**
         * 设置格式化提供者
         * 
         * @param formatProviders
         *            Key为匹配范围符
         */
        void setFormatProviders(Map<String, FormatProvider> formatProviders);

        /**
         * 添加格式化提供者
         * @param prefix 前缀
         * @param formatProvider
         */
        void addFormatProvider(String prefix, FormatProvider formatProvider);
    }




    三个方法, setPatternHandle用于设定格式话模式,setFormatProviders用于设定格式化提供者,由于是一个map,key值是前缀,value是对应的格式化处理器。当然也可以通过addFormatProvider一个一个的增加出来。
    好的,接口的事情就搞定了,我们来看看具体的实现类:
    默认的格式化实现类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    public class DefaultPatternDefine implements PatternDefine {

        private static final String DEFAULT_PATTERN_STRING = "([$]+[{]+[a-zA-Z0-9[.[_[:[/[#]]]]]]+[}])";
        private static final String DEFAULT_POSTFIX_PATTERN_STRING = "}";
        private static final String DEFAULT_PREFIX_PATTERN_STRING = "${";
        private static final char DEFAULT_SPLIT_CHAR = ':';
        private String prefixPatternString = DEFAULT_PREFIX_PATTERN_STRING;// 前缀
        private String postfixPatternString = DEFAULT_POSTFIX_PATTERN_STRING;// 后缀
        private String patternString = DEFAULT_PATTERN_STRING;// 中间部分
        private Pattern pattern;
        private char splitChar = DEFAULT_SPLIT_CHAR;// 域分隔符

        public Pattern getPattern() {
            if (pattern == null) {
                pattern = Pattern.compile(patternString);
            }
            return pattern;
        }

        public void setPrefixPatternString(String prefixPatternString) {
            this.prefixPatternString = prefixPatternString;
        }

        public void setPostfixPatternString(String postfixPatternString) {
            this.postfixPatternString = postfixPatternString;
        }

        public void setPatternString(String patternString) {
            this.patternString = patternString;
        }

        public String getPureMatchText(String string) {
            int startPos = prefixPatternString.length();
            int endPos = string.length() - postfixPatternString.length();
            return string.substring(startPos, endPos);
        }

        public String getFullMatchText(String string) {
            return String.format("%s%s%s", prefixPatternString, string,
                    postfixPatternString);
        }

        public void setSplitChar(char splitChar) {
            this.splitChar = splitChar;
        }

        public char getSplitChar() {
            return splitChar;
        }

    }




    下面是一个针对Context的格式串:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class ContextFormater implements FormatProvider {

        public String format(Context context, String string) throws FormatException {
            Object obj = context.get(string);
            if (obj != null) {
                return obj.toString();
            }
            int index = string.indexOf('.');
            if (index > 0) {
                String name = string.substring(0, index);
                obj = context.get(name);
                if (obj != null) {
                    String property = string.substring(index + 1);
                    try {
                        return BeanUtils.getProperty(obj, property).toString();
                    } catch (Exception e) {
                        throw new FormatException(e);
                    }
                }
            }
            return null;
        }
    }




    下面是核心的格式化算法了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    public class FormaterImpl implements Formater {

        private Map<String, FormatProvider> formatProviders;
        private PatternDefine patternDefine = new DefaultPatternDefine();

        /**
         * 构造函数 使用默认的配置加载器
         */
        public FormaterImpl() {
        }

        /**
         * 格式化找到的内容,其余内容不变,如果找不到内容,则原样保留
         * 
         * @throws FormatException
         */
        public String format(Context context, String source) throws FormatException {
            Matcher matcher = patternDefine.getPattern().matcher(source);
            StringBuffer buf = new StringBuffer();
            int curpos = 0;
            while (matcher.find()) {
                String replaceStr = patternDefine.getPureMatchText(matcher.group());
                buf.append(source.substring(curpos, matcher.start()));
                curpos = matcher.end();
                String str = formatSingle(context, replaceStr);
                if (str != null) {
                    buf.append(str);
                }
                continue;
            }
            buf.append(source.substring(curpos));
            return buf.toString();
        }

        /**
         * 格式化字符串
         * 
         * @param string
         *            String
         * @return String
         * @throws FormatException
         * @throws Exception
         */
        private String formatSingle(Context context, String string)
                throws FormatException {
            String s[] = string.split(patternDefine.getSplitChar() + "");
            if (s.length >= 2) {
                FormatProvider o = (FormatProvider) formatProviders.get(s[0]);
                if (o != null) {
                    return o.format(context, s[1]);
                }
            } else {
                FormatProvider o = (FormatProvider) formatProviders.get("");
                if (o != null) {
                    return o.format(context, string);
                }
            }
            return patternDefine.getFullMatchText(string);
        }

        public void setFormatProviders(Map<String, FormatProvider> formatProviders) {
            this.formatProviders = formatProviders;
        }

        public void setPatternHandle(PatternDefine patternHandle) {
            this.patternDefine = patternHandle;

        }

        public void addFormatProvider(String prefix, FormatProvider formatProvider) {
            if (formatProviders == null) {
                formatProviders = new HashMap<String, FormatProvider>();
            }
            formatProviders.put(prefix, formatProvider);
        }

    }




    好吧,还有一些配置相关的类,由于不是关键性的,就不在这里讲了,那么接下来看示例:

    增加一个常量格式化提供者:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class ConstFormatProvider implements FormatProvider {
        Map<String, String> constMap = new HashMap<String, String>();

        public String format(Context context, String key) {
            return constMap.get(key);
        }

        public Map<String, String> getConstMap() {
            return constMap;
        }

        public void setConstMap(Map<String, String> constMap) {
            this.constMap = constMap;
        }

    }




    再增加一个日期格式化提供者:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class DateFormatProvider implements FormatProvider {
        Map<String, String> constMap = new HashMap<String, String>();

        public String format(Context context, String key) {
            return constMap.get(key);
        }

        public Map<String, String> getConstMap() {
            return constMap;
        }

        public void setConstMap(Map<String, String> constMap) {
            this.constMap = constMap;
        }

    }




    再增加一个用于测试的POJO类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class User {
        String name;
        int age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public User() {

        }

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }




    好吧,我承认,前面都是做铺垫,跑龙套的,真正的秀场下面开始:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    /**
         * 测试不存在任何标记情况
         * 
         * @throws FormatException
         */
        public void testFormatNotPlaceholder() throws FormatException {
            assertEquals("this is test", formater.format(context, "this is test"));
        }

        /**
         * 测试存在标记,且有处理提供者处理的情况
         * 
         * @throws FormatException
         */
        public void testFormatExistPlaceholderProvider() throws FormatException {
            Context context = new ContextImpl();
            assertEquals("this is v1 test",
                    formater.format(context, "this is ${const:1} test"));
        }

        /**
         * 测试存在标记,且没有处理提供者处理的情况
         * 
         * @throws FormatException
         */

        public void testFormatExistPlaceholderNoProvider() throws FormatException {
            assertEquals("this is ${abc:2} test",
                    formater.format(context, "this is ${abc:2} test"));
        }

        /**
         * 测试存在标记,且是bean的情况
         * 
         * @throws FormatException
         */

        public void testFormatBean() throws FormatException {
            User user = new User("aa", 123);
            context.put("user", user);
            assertEquals("this is aa test 123",
                    formater.format(context, "this is ${context:user.name} test ${context:user.age}"));

        }




    下面总结一下:
    上面的格式化占位符方式是${...}方式的,中间的...可以是aa:bb的方式,或者直接是bb的方式,冒号前面实际是一个区域的概念,表示由对应的区域处理器进行处理。这样就可以由开发人员不断的扩展格式化处理器的处理能力。由于占位匹配器也是可以进行扩展的,因此,可以自行定义自己的格式化占位方式。
    对于对象的属性可以无限向下“.”下去,当然也可以添加其它的处理方式,比如:数组之类的。
    所以从功能及定位来说,与@Brin想写程序 是一样的。
    剧透一下:当时我本来是想写模板语言的,后来直接选择复用Velocity了,所以,就只到此为止了。
    虽然放弃了,但是其中在设计及基础构架方面的一些思想及模式,还是值得同学们参考与借鉴的。

  • 相关阅读:
    tensorflow2.0 GPU和CPU 时间对比
    第一次使用FileZilla Server
    PremiumSoft Navicat 15 for Oracle中文破解版安装教程
    Unmapped Spring configuration files found. Please configure Spring facet or use 'Create Default Context' to add one including all unmapped files.
    ng : 无法加载文件 D: odejs ode_global g.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
    angular
    Github上优秀的go项目
    win10---file explore 中remove quick access folder
    react--useEffect使用
    linux---cat 和 grep 的妙用
  • 原文地址:https://www.cnblogs.com/j2eetop/p/4612575.html
Copyright © 2011-2022 走看看