我是愛偷懶的勤快人
咱們的口號是:
能用腦子解決的絕對不靠體力,能用電腦完成的絕對不靠腦子,能懶就懶,懶出奇跡
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();
}
}
}
複製代碼