本文说明
1.1.问题
今天遇到一个问题,就是如何指定批量代换某些字符串。
场景:比如下面一段markdown,写文章时遇到很多固定的链接时,总是很长一段。
特别是表格里,感觉要崩溃啊,而且万一哪天要换个网址,一个个改还不改疯掉。
不行,得想个办法,再怎么说咱也是会敲些Hello World
代码的人,逼格不能输。
Padding是一个可以产生内边距的控件
详情可见:![Padding](https://juejin.im/user/5b42c0656fb9a04fe727eb37/collections)
[Container](https://juejin.im/user/5b42c0656fb9a04fe727eb37)有一个padding属性,
详情可见![Padding](https://juejin.im/user/5b42c0656fb9a04fe727eb37/collections)
1.2.想法
我就想写成下面的样子,带有
$[XXX]
的全给我自动换成相应的连接,看着也清爽,
所以咬个牙,搞一波,一劳永逸。最终结果是只要点一下,一个文件夹里所有markdown文件都转化。
Padding是一个可以产生内边距的控件
详情可见:$[Padding]
$[Container]有一个padding属性,
详情可见$[Padding]
2.实现
2.1:字符串匹配
首先要将
$[XXX]
中的XXX拿出来
String test="Padding是一个可以产生内边距的控件\n" +
"详情可见:$[Padding]\n" +
"$[Container]有一个padding属性,\n" +
"详情可见$[Padding]";
parse(test);
private static void parse(String target) {
String regex = "\\$\\[(?<result>.*?)\\]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(target);
while (matcher.find()) {
String matchStr=matcher.group("result");
}
}
---->[打印结果]----
Padding
Container
Padding
2.2:之后怎么办
到这里卡壳了,感觉匹配出来也没什么用,在replace方法耗了些时间,然并卵
如果链接少的话replaceAll一个一个换也行,但很多就有点恐怖了
然后看到matcher的end()方法,内心一喜,有索引似乎有搞头,二话不说,存起来先
private static void parse(String target) {
Map<Integer,String> cutPos=new TreeMap<>();//断点映射
String regex = "\\$\\[(?<result>.*?)\\]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(target);
while (matcher.find()) {
String matchStr=matcher.group("result");
catPos.put(matcher.end(),matchStr);//放入映射
}
}
2.3:最终处理
调试了一会,摸索到了一个方法:
断点可以将字符串分为两半,前段处理后再和后段拼在一起,这样第一个就ok了
然后处理拼成的字符串,这有一个问题:就是此时的断点索引要偏移,
因为原先的字符串已经改变了,当然这也难不倒聪明伶俐的我
private static void parse(String target) {
Map<Integer,String> cutPos=new TreeMap<>();
Map<String,String> urlMap=new HashMap<>();
urlMap.put("Padding","https://juejin.im/user/5b42c0656fb9a04fe727eb37/collecti
urlMap.put("Container","https://juejin.im/user/5b42c0656fb9a04fe727eb37");
String regex = "\\$\\[(?<result>.*?)\\]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(target);
while (matcher.find()) {
String matchStr=matcher.group("result");
System.out.println(matchStr);
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 class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="$["+v+"]";
String dest= "!["+v+"]"+"("+urlMap.get(v)+")";
String substring = target.substring(0,k+offset);
temp = substring.replace(src, dest);
target = target.replace(substring, temp);
offset+=dest.length()-src.length();
}
}
然后一跑,大功告成,好了,正文即将开始
3.优化与封装
好了,已经拥有核心科技,就差包个壳了
3.1:Parser类
用于字符串的解析,注意可以自定义符号,不过记得转义
public class Parser {
/**
* 默认:$[X],自定义注意\\转义
*/
private String symbol;
public Parser() {
this.symbol = "\\$\\[X\\]";
}
public Parser(String symbol) {
this.symbol = symbol;
}
/**
* 解析字符串
* @param target 目标字符串
* @param matchMap 匹配映射
* @return 处理后的字符串
*/
public String parse(String target, Map<String,String> matchMap) {
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 class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="$["+v+"]";
String dest= "!["+v+"]"+"("+matchMap.get(v)+")";
String substring = target.substring(0,k+offset);
temp = substring.replace(src, dest);
target = target.replace(substring, temp);
offset+=dest.length()-src.length();
}
return target;
}
}
3.2:文件操作
对于我即将开源的Flutter组件集项目,每个文件里都涉及到很多别的组件或属性链接
所以我需要寻找一个解决方法,不然一个一个套,感觉不太实际,而且眼花缭乱
最终导致写代码的心情不佳,所以来个批量文件操作吧
public String parserFile(String path, Map<String,String> matchMap)
return parserFile(new File(path),matchMap);
}
/**
* 根据文件解析
* @param file 文件
* @param matchMap 匹配映射
* @return
*/
public String parserFile(File file, Map<String,String> matchMap){
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(),matchMap);
}
3.3:文件夹批量文件操作
OK,打完收工,现在可以开开心心写md文件了,字符串操作真的很好玩
如果今后遇到什么需要替换的,照这个思路来就ok了,避免不必要的劳动付出。
public void parserDir(String path, Map<String, String> matchMap) {
copyDir(path, path + "-src");//先拷贝一分
parserDir(new File(path), matchMap);
}
private void parserDir(File file, Map<String, String> matchMap) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files == null) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
parserDir(f, matchMap);
} else {
if (f.getName().endsWith(".md")) {
handleFile(matchMap, f);
}
}
}
} else {
parserFile(file, matchMap);
}
}
private void handleFile(Map<String, String> matchMap, File f) {
FileWriter fw = null;
String result = parserFile(f, matchMap);
try {
fw = new FileWriter(f);//写出到磁盘
fw.write(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 复制整个文件夹内容
*
* @param oldPath String 原文件路径
* @param newPath String 复制后路径
* @return boolean
*/
public 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();
}
}
共同学习,写下你的评论
评论加载中...
作者其他优质文章