Tiny Formater

简介:

格式化提供者,用于对字符串进行转换:

?
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了,所以,就只到此为止了。

虽然放弃了,但是其中在设计及基础构架方面的一些思想及模式,还是值得同学们参考与借鉴的。


相关文章
|
3月前
|
机器学习/深度学习 API TensorFlow
【Tensorflow+keras】解决 Fail to find the dnn implementation.
在TensorFlow 2.0环境中使用双向长短期记忆层(Bidirectional LSTM)遇到“Fail to find the dnn implementation”错误时的三种解决方案。
71 0
|
5月前
|
机器学习/深度学习 编解码 测试技术
【YOLOv8改进】LSKNet(Large Selective Kernel Network ):空间选择注意力 (论文笔记+引入代码)
YOLO目标检测专栏介绍了YOLO的有效改进和实战应用,包括卷积、主干网络、注意力机制和检测头的创新。提出的新模型LSKNet利用大型选择性核关注遥感场景的先验知识,动态调整感受野,提升目标检测效果。创新点包括LSKblock Attention、大型选择性核网络和适应性感受野调整。LSKNet在多个遥感检测基准上取得最优性能,且结构轻量。此外,文章提供了YOLOv8的LSKNet实现代码。更多详情可查阅相关专栏链接。
|
5月前
|
开发框架 JSON .NET
探索Semantic Kernel内置插件:深入了解HttpPlugin的应用
其他 Put和Delete类似。 最后 可以借鉴HttpPlugin的实现思路在项目中灵活的运行,如果不支持那就可以自定义插件来完成需求的开发,还是比较期待这个插件能够更加完善的一点,在未来以更灵活的方式支持Post等请求的多种形式。
|
6月前
[Transformer-XL]论文实现:Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context
[Transformer-XL]论文实现:Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context
33 1
|
6月前
|
机器学习/深度学习 并行计算 关系型数据库
【RetNet】论文解读:Retentive Network: A Successor to Transformer for Large Language Models
【RetNet】论文解读:Retentive Network: A Successor to Transformer for Large Language Models
179 1
|
机器学习/深度学习 存储 JSON
YOLOv5的Tricks | 【Trick10】从PyTorch Hub加载YOLOv5
YOLOv5的Tricks | 【Trick10】从PyTorch Hub加载YOLOv5
1162 0
YOLOv5的Tricks | 【Trick10】从PyTorch Hub加载YOLOv5
|
并行计算 PyTorch 算法框架/工具
【PyTorch】cuda()与to(device)的区别
【PyTorch】cuda()与to(device)的区别
297 0
|
并行计算 Ubuntu 算法框架/工具
Caffe:使用 cudnn 5.1 配置 Faster-RCNN Caffe 并运行 demo
系统:Ubuntu 16.04 环境:CUDA 8.0 + cudnn 5.1 + BLAS + opencv 3.0.0
147 0
【yolov5报错】Can‘t get attribute ‘SPPF‘ on <module ‘models.common‘ from ‘--yolov5-5.0\models\common.py
【yolov5报错】Can‘t get attribute ‘SPPF‘ on <module ‘models.common‘ from ‘--yolov5-5.0\models\common.py
1132 0
|
TensorFlow 算法框架/工具 计算机视觉
CV之NS之VGG16:基于TF Slim(VGG16)利用七个不同的预训练模型实现快速NS风格
CV之NS之VGG16:基于TF Slim(VGG16)利用七个不同的预训练模型实现快速NS风格
CV之NS之VGG16:基于TF Slim(VGG16)利用七个不同的预训练模型实现快速NS风格