玩轉字符串篇--替換的鬼斧神工

本文說明

1.1.問題

今天遇到一個問題,就是如何指定批量代換某些字符串。
場景:好比下面一段markdown,寫文章時遇到不少固定的連接時,老是很長一段。
特別是表格裏,感受要崩潰啊,並且萬一哪天要換個網址,一個個改還不改瘋掉。
不行,得想個辦法,再怎麼說咱也是會敲些Hello World代碼的人,逼格不能輸。bash

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文件都轉化。markdown

Padding是一個能夠產生內邊距的控件
詳情可見:$[Padding]
$[Container]有一個padding屬性,
詳情可見$[Padding]
複製代碼

2.實現

2.1:字符串匹配

首先要將$[XXX]中的XXX拿出來app

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了
而後處理拼成的字符串,這有一個問題:就是此時的斷點索引要偏移,
由於原先的字符串已經改變了,固然這也難不倒聰明伶俐的我ui

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 src="$["+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(); } } 複製代碼

而後一跑,大功告成,好了,正文即將開始this


3.優化與封裝

好了,已經擁有核心科技,就差包個殼了url

3.1:Parser類

用於字符串的解析,注意能夠自定義符號,不過記得轉義spa

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 src="$["+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了,避免沒必要要的勞動付出。code

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();
    }
}
複製代碼
相關文章
相關標籤/搜索