我是爱偷懒的勤快人
咱们的口号是:
能用脑子解决的绝对不靠体力,能用电脑完成的绝对不靠脑子,能懒就懒,懒出奇迹
java
你眼中的代码是什么,类的逻辑关系?方法的实现?不要忽略一个重要的本质:
代码是人能够读懂的可编译成可执行文件的字符串
,因此字符串很重要。
陆陆续续写了好几篇关于字符串的文章了,量变的基类每每带来质变的升华
今天我灵光一闪,便有此文。为了避免让优秀石沉大海,以前写的几篇链接放在下面:bash
1.玩转字符串篇--代码自动生成,解放双手
2.玩转字符串篇--数据遍地是,看你取不取
3.玩转字符串篇--练习MySQL没素材?来一波字符串操做 link
4.玩转字符串篇--替换的鬼斧神工app
今天写Flutter自定义组件,感受写个StatefulWidget要罗里吧嗦一大堆
并且一开始都是差很少的,因而想来个一键生成,并放到gradle里
写着写着发现用上次的字符串替代类能够用,不用走平时的拼接了
果真有心栽花花不开,无意插柳柳成荫!本文主要的是对字符串的想法函数
TemplateParser
这是我再玩转字符串篇--替换的鬼斧神工的基础上进行完善的产物工具
1).可指定匹配符
2).优化告终构,使用Properties替换了HashMap,并使用配置文件
3).支持单文件和文件夹多文件替换
复制代码
在此以前,先说一下Properties的使用,感受这个也挺好的,能够根据配置文件读成映射表
他继承自HashTable,只存放String到String的映射,下面来看一下他的用法
这里在项目最外面建立一个config.properties
,写着键值对className=TolyWidget
post
public class Generation {
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
//读取属性文件a.properties
InputStream in = new BufferedInputStream(new FileInputStream("config.properties"));
prop.load(in); ///加载属性列表
Iterator<String> it = prop.stringPropertyNames().iterator();
while (it.hasNext()) {
String key = it.next();
System.out.println(key + ":" + prop.getProperty(key));
}
in.close();
}
}
---->[控制台输出]----
className:TolyWidget
复制代码
这样就能够根据配置文件在代码中使用字符串的键值对了gradle
最终的效果是能够经过配置文件的映射字符串,替换掉一个模板中的全部相应被标识部分
默认配置文件的位置在项目根部,名称config.properties
,输出到模板的父目录同级的dest下优化
package generation;
import java.io.*;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TemplateParser {
/**
* 默认:$[X],自定义注意\\转义
*/
private String symbol;
private Properties properties;
public TemplateParser() {
this("\\$\\[X\\]", "config.properties");
}
public TemplateParser(String symbol, String propFilePath) {
this.symbol = symbol;
loadProperties(propFilePath);
}
/**
* 载入配置文件
* @param path 配置文件路径
*/
private void loadProperties(String path) {
properties = new Properties();
//读取属性文件a.properties
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(path));
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 解析字符串
*
* @param target 目标字符串
* @return 处理后的字符串
*/
public String parser(String target) {
String[] symbols = symbol.split("X");
Map<Integer, String> cutPos = new TreeMap<>();
String regex = symbols[0] + "(?<result>.*?)" + symbols[1];
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(target);
while (matcher.find()) {
String matchStr = matcher.group("result");
cutPos.put(matcher.end(), matchStr);
}
Iterator<Map.Entry<Integer, String>> iterator = cutPos.entrySet().iterator();
String temp;
int offset = 0;
while (iterator.hasNext()) {
Map.Entry<Integer, String> e = iterator.next();
int k = e.getKey();
String v = e.getValue();
String src = "$[" + v + "]";
String result = properties.getProperty(v);
String substring = target.substring(0, k + offset);
temp = substring.replace(src, result);
target = target.replace(substring, temp);
offset += result.length() - src.length();
}
return target;
}
/**
* 根据路径解析全部文件
* @param path 路径
*/
public void parserDir(String path) {
copyDir(path, path + "-dest");//先拷贝一分
parserDir(new File(path + "-dest"));
}
private void parserDir(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files == null) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
parserDir(f);
} else {
saveFile(f, parserFile(file));
}
}
} else {
parserFile(file);
}
}
/**
* 解析一个文件
*
* @param path 路径
* @return 解析后的字符串
*/
public String parserFile(String path) {
File file = new File(path);
String result = parserFile(new File(path));
String out = file.getParentFile().getParentFile().getAbsolutePath() + File.separator + "dest" + File.separator + file.getName();
saveFile(new File(out), result);
return result;
}
/**
* 根据文件解析
*
* @param file 文件
* @return 解析后的字符串
*/
private String parserFile(File file) {
InputStream is = null;
StringBuilder sb = new StringBuilder();
try {
is = new FileInputStream(file);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
sb.append(new String(buffer, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return parser(sb.toString());
}
//==========================文件相关操做===========================
/**
* 保存字符串文件
*
* @param file 文件
* @param content 字符串内容
*/
private void saveFile(File file, String content) {
ifNotExistMakeIt(file);
FileWriter fw = null;
try {
fw = new FileWriter(file);//写出到磁盘
fw.write(content);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 判断文件是否存在,不存在则建立它
*
* @param file
*/
private static void ifNotExistMakeIt(File file) {
if (file.exists()) {//2.判断文件是否存在
return;
}
File parent = file.getParentFile();//3.获取父文件
if (!parent.exists()) {
if (!parent.mkdirs()) {//4.建立父文件
return;
}
}
try {
file.createNewFile();//5.建立文件
} catch (IOException e) {
e.printStackTrace();
}
}
private static void ifNotExistMakeIt(String path) {
File file = new File(path);//1.建立文件
ifNotExistMakeIt(file);
}
/**
* 复制整个文件夹内容
*
* @param oldPath String 原文件路径
* @param newPath String 复制后路径
* @return boolean
*/
private void copyDir(String oldPath, String newPath) {
try {
(new File(newPath)).mkdirs(); //若是文件夹不存在 则创建新文件夹
File a = new File(oldPath);
String[] file = a.list();
File temp = null;
if (file == null) {
return;
}
for (int i = 0; i < file.length; i++) {
if (oldPath.endsWith(File.separator)) {
temp = new File(oldPath + file[i]);
} else {
temp = new File(oldPath + File.separator + file[i]);
}
if (temp.isFile()) {
FileInputStream input = new FileInputStream(temp);
FileOutputStream output = new FileOutputStream(newPath + "/" +
(temp.getName()).toString());
byte[] b = new byte[1024 * 5];
int len;
while ((len = input.read(b)) != -1) {
output.write(b, 0, len);
}
output.flush();
output.close();
input.close();
}
if (temp.isDirectory()) {//若是是子文件夹
copyDir(oldPath + "/" + file[i], newPath + "/" + file[i]);
}
}
} catch (Exception e) {
System.out.println("复制出错");
e.printStackTrace();
}
}
}
复制代码
里面有不少文件经常使用的操做,也能够抽出一个工具类收藏一下ui
关于Gradle的知识我有一篇专文:杂篇:一代版本一代神[-Gradle-]this
新建一个task在左边Gradle->other会有相应的任务,点一下就能够运行其中的代码
能够用System.getProperty("user.dir")
获取当前项目的根目录
---->[app/build.gradle最后面]----
task generationTask() {//自定义一个任务
doFirst {
String root=System.getProperty("user.dir");
println("hello gradel:"+root)
}
复制代码
因为Gradle中使用的是和Java兼容的Groovy语言,因此Java代码也是能运行的
这里在项目根文件下建立generation文件夹用来盛放配置文件以及模板和输出文件
task generationTask() {//自定义一个任务
doFirst {
String root=System.getProperty("user.dir");
println("hello gradel:"+root)
Properties prop = new Properties();
//读取属性文件a.properties
InputStream is = new BufferedInputStream(new FileInputStream(root+"/generation/config.properties"));
prop.load(is); ///加载属性列表
Iterator<String> itor = prop.stringPropertyNames().iterator();
while (itor.hasNext()) {
String key = itor.next();
System.out.println(key + ":" + prop.getProperty(key));
}
is.close();
}
}
复制代码
而后运行就能够看到获取的结果:
className:TolyWidget
把刚才写的类所有拷到下面。说几个比较坑的点吧
1.Groovy中正则匹配不能用分组,我勒个去
2.符号$要用单引号,不然报错
3.函数不能重载,我勒个去
复制代码
那么大一段写在一块不怎么雅观,拆一下呗,将插件逻辑所有抽到另外一个文件了
也放在generation包里,这样整个流程所须要的东西都在一块儿,整个gradle只管用就好了
咱们只须要在乎模板和配置,两个都写好以后,轻轻一点,模板中须要替换的所有搞定
---->[使用方法,app/build.gradle]----
apply from: "./generation/generation.gradle"
复制代码
把这个拷过去用就好了,之后有什么写着比较烦并且没有技术含量的批量换一下呗。
// Create By 张风捷特烈(toly) in 2019.7.17 ---------
apply plugin: TemplateParserPlugin//声明使用插件
//----------------------------如下是插件部分--------------------------------
class TemplateParserPlugin implements Plugin<Project> {
//该接口定义了一个apply()方法,在该方法中,咱们能够操做Project,
//好比向其中加入Task,定义额外的Property等。
void apply(Project project) {
//加载Extension
project.extensions.create("Config", Extension)
//使用Extension配置信息
project.task('TemplateParser') << {
String path = project.Config.root
new TemplateParser(path+"config.properties")
.parserFile(path+"template/StatefulTemplate.txt")
}
}
}
class Extension {//拓展参数
String root = System.getProperty("user.dir")+"/generation/"
}
///----------------- 如下是解析类 -----------------
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TemplateParser {
/**
* 默认:$[X],自定义注意\\转义
*/
private String symbol;
private Properties properties;
public TemplateParser() {
this('\\$\\[X\\]', "config.properties");
}
public TemplateParser( String propFilePath) {
this('\\$\\[X\\]',propFilePath);
}
public TemplateParser(String symbol, String propFilePath) {
this.symbol = symbol;
loadProperties(propFilePath);
}
/**
* 载入配置文件
* @param path 配置文件路径
*/
private void loadProperties(String path) {
properties = new Properties();
//读取属性文件a.properties
InputStream is = null;
try {
is = new BufferedInputStream(new FileInputStream(path));
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 解析字符串
*
* @param target 目标字符串
* @return 处理后的字符串
*/
public String parser(String target) {
String[] symbols = symbol.split("X");
Map<Integer, String> cutPos = new TreeMap<>();
String regex = symbols[0] + ".*?" + symbols[1];
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(target);
while (matcher.find()) {
String matchStr = matcher.group(0);
String v = matchStr.split(symbols[0])[1].split(symbols[1])[0]
cutPos.put(matcher.end(), v);
}
Iterator<Map.Entry<Integer, String>> iterator = cutPos.entrySet().iterator();
String temp;
int offset = 0;
while (iterator.hasNext()) {
Map.Entry<Integer, String> e = iterator.next();
int k = e.getKey();
String v = e.getValue();
String src = '$[' + v + "]";
String result = properties.getProperty(v);
String substring = target.substring(0, k + offset);
temp = substring.replace(src, result);
target = target.replace(substring, temp);
offset += result.length() - src.length();
}
return target;
}
/**
* 根据路径解析全部文件
* @param path 路径
*/
public void parserDir(String path) {
copyDir(path, path + "-dest");//先拷贝一分
_parserDir(new File(path + "-dest"));
}
private void _parserDir(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files == null) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
parserDir(f);
} else {
saveFile(f, parserFile(file));
}
}
} else {
parserFile(file);
}
}
/**
* 解析一个文件
*
* @param path 路径
* @return 解析后的字符串
*/
public String parserFile(String path) {
File file = new File(path);
String result = _parserFile(new File(path));
String out = file.getParentFile().getParentFile().getAbsolutePath() + File.separator + "dest" + File.separator + file.getName();
saveFile(new File(out), result);
return result;
}
/**
* 根据文件解析
*
* @param file 文件
* @return 解析后的字符串
*/
private String _parserFile(File file) {
InputStream is = null;
StringBuilder sb = new StringBuilder();
try {
is = new FileInputStream(file);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
sb.append(new String(buffer, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return parser(sb.toString());
}
//=============================================文件相关操做=============================================
/**
* 保存字符串文件
*
* @param file 文件
* @param content 字符串内容
*/
private void saveFile(File file, String content) {
ifNotExistMakeIt(file);
FileWriter fw = null;
try {
fw = new FileWriter(file);//写出到磁盘
fw.write(content);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 判断文件是否存在,不存在则建立它
*
* @param file
*/
private static void ifNotExistMakeIt(File file) {
if (file.exists()) {//2.判断文件是否存在
return;
}
File parent = file.getParentFile();//3.获取父文件
if (!parent.exists()) {
if (!parent.mkdirs()) {//4.建立父文件
return;
}
}
try {
file.createNewFile();//5.建立文件
} catch (IOException e) {
e.printStackTrace();
}
}
private static void ifNotExistMakeIt(String path) {
File file = new File(path);//1.建立文件
ifNotExistMakeIt(file);
}
/**
* 复制整个文件夹内容
*
* @param oldPath String 原文件路径
* @param newPath String 复制后路径
* @return boolean
*/
private void copyDir(String oldPath, String newPath) {
try {
(new File(newPath)).mkdirs(); //若是文件夹不存在 则创建新文件夹
File a = new File(oldPath);
String[] file = a.list();
File temp = null;
if (file == null) {
return;
}
for (int i = 0; i < file.length; i++) {
if (oldPath.endsWith(File.separator)) {
temp = new File(oldPath + file[i]);
} else {
temp = new File(oldPath + File.separator + file[i]);
}
if (temp.isFile()) {
FileInputStream input = new FileInputStream(temp);
FileOutputStream output = new FileOutputStream(newPath + "/" +
(temp.getName()).toString());
byte[] b = new byte[1024 * 5];
int len;
while ((len = input.read(b)) != -1) {
output.write(b, 0, len);
}
output.flush();
output.close();
input.close();
}
if (temp.isDirectory()) {//若是是子文件夹
copyDir(oldPath + "/" + file[i], newPath + "/" + file[i]);
}
}
} catch (Exception e) {
System.out.println("复制整个文件夹内容操做出错");
e.printStackTrace();
}
}
}
复制代码