Batch replace string specified in MarkDown document

Keywords: Java IDE markdown

Batch replace string specified in MarkDown document

preface

Recently, I bought a new computer. It took almost a weekend to upgrade various configurations. At the same time, I want to import the previous blog documents. Because the blog documents are written in Typora, and the pictures are also stored locally. After the picture path changes, all the pictures in the document can't be found. I wonder if I can solve this problem through tools

Problems to be solved

After the document is migrated, the images in the original document become like this

This happens because the specified file path cannot be found. Therefore, I wonder if it can be solved by document replacement

Solutions and ideas

mode

Open the Typora editor and replace the picture path with a new path through the find and replace function. The picture can be displayed normally

So here's the problem. Replace them manually one by one? This is also the beginning. Under this background, I wrote a code to replace the specified content in the document in batch. Later, the test was successful. Here is a record.

thinking

Step 1: find all files recursively; Step 2: prepare the source and target files; Step 3: replace the matching content and output the file to the specified new file

Concrete implementation

The above ideas have the following implementation

Recursively find all files

It shouldn't be difficult for us to directly the code. We just added a judgment whether it is a markdown file

private static Set<String> markDownFileSuffix = new HashSet<>();


static {
    //Only md files are processed
    markDownFileSuffix.add("md");
}

/**
 * Recursively read all files in the folder
 *
 * @param path
 */
public static void readFileInDir(String path, List<File> fileList) {
    File f = new File(path);
    //Get all files under the file
    File[] files = f.listFiles();

    for (File file : files) {
        if (file.isDirectory()) {
            readFileInDir(file.getAbsolutePath(), fileList);
        } else {
            if (isMarkDownFile(file.getName())) {
                fileList.add(file);
            }
        }
    }
}

/**
 * Determine whether it is a markdown document
 *
 * @param fileName
 * @return
 */
public static boolean isMarkDownFile(String fileName) {
    boolean result = false;
    String suffix = fileName.substring(fileName.lastIndexOf('.') + 1);
    if (markDownFileSuffix.contains(suffix)) {
        result = true;
    }
    return result;
}

Prepare the source and destination files

Due to an obsessive-compulsive disorder and in order to avoid the confusion of the previously classified folders, it is required that the source files are stored in that folder, and the new files are also stored in that classified folder, but the root directory is different.

Therefore, it is the last word to prepare the target document before formally processing the document

/**
 * Create the target file according to the original file path
 * @param sourceFile source file
 * @param targetFileDir Destination file root path
 * @return Create a good target file
 */
public static File createTargetFile(File sourceFile,String targetFileDir){
    //Get absolute path of source file
    String sourceFileAbsoluteName = sourceFile.getAbsolutePath();
    //Replace the root path. Here, for simple and direct hard coding, the first parameter can be passed in externally
    String afterDealFileName = sourceFileAbsoluteName.replace("F:\\blog_doc", targetFileDir);
    //Intercept the folder path and file name
    int splitIndex = afterDealFileName.lastIndexOf("\\");
    //Folder path
    String dirPath = afterDealFileName.substring(0,splitIndex+1);
    //file name
    String createFileName = afterDealFileName.substring(splitIndex+1);
    log.info("The target file name to be created is:{},Exist in:{}folder",createFileName,dirPath);
    //Create folder recursively first
    File dirFile = new File(dirPath);
    if(!dirFile.exists()){
        dirFile.mkdirs();
        log.info("folder:{}Creation complete",dirPath);
    }
    //Create target file
    File targetFile = new File(dirPath,createFileName);
    if(!targetFile.exists()){
        try {
            targetFile.createNewFile();
        } catch (IOException e) {
            log.error("file:{}Create exception:{}",targetFile.getAbsolutePath(),e);
            return null;
        }
        log.info("file:{}Creation complete",targetFile.getAbsolutePath());
    }
    //Returns the created file
    return targetFile;
}

Replace matching content

Replace the specified content in the source document and output it to a new document

/**
 * Start replacing contents in file
 * @param sourceFile source file
 * @param targetRegex A matching regular expression is required
 * @param toReplaceStr String to replace with
 */
public static void replaceImgPath(File sourceFile, String targetRegex, String toReplaceStr) {
    String regex = targetRegex;
    String targetFileDir = "F:\\Blog document_new";//The target folder and processed files will be written to this folder, and the classification will be guaranteed according to the original file path
    BufferedReader reader = null;
    BufferedWriter writer = null;
    log.info("Start processing file:{},The final file will exist in the directory:{}in",sourceFile.getAbsoluteFile(),targetFileDir);
    String fileName = sourceFile.getAbsoluteFile() + "/" + sourceFile.getName();
    try {
        //Construct source file reader
        reader = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile)));
        //Create target file
        File targetFile = createTargetFile(sourceFile,targetFileDir);
        if(null == targetFile){
            log.info("file:{},Failed to create target file, please operate manually",sourceFile.getAbsolutePath());
            return;
        }
        //Construct target file writer
        writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile)));
        String tempStr = "";
        String regStr = regex;//It's a little redundant and can be deleted
        Pattern pattern = Pattern.compile(regStr);
        while ((tempStr = reader.readLine()) != null) {
            tempStr += "\n"; //Add line breaks to avoid formatting confusion
            Matcher matcher = pattern.matcher(tempStr);
            if (matcher.find()) {//If it matches, replace it
                //Replace as specified
                tempStr = tempStr.replaceAll(regex, toReplaceStr);
                log.info("file:{},The replaced string is:{}",sourceFile.getAbsoluteFile(), tempStr);
                count++;//Count the number of matches
            }
            writer.write(tempStr);
        }
        writer.flush();
    } catch (Exception e) {
        //Record exception
        log.error("file:{},Character replacement exception. The exception information is:{},Please operate manually", fileName,e);
        return;
    } finally {
        //Close flow
        try {
            reader.close();
        } catch (IOException e) {
            log.error("file:{},Flow closing exception", fileName);
        }
        try {
            writer.close();
        } catch (IOException e) {
            log.error("file:{},Flow closing exception", fileName);
        }
    }
}

Test situation

Complete code

package com.learn.sample;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * autor:liman
 * createtime:2021-10-31
 * comment: Read the written markdown document and perform regular replacement for the specified characters
 */
@Slf4j
public class ReplaceDocFileTools {

    private static Set<String> markDownFileSuffix = new HashSet<>();

    private static Integer count = 0;

    static {
        //Only md files are processed
        markDownFileSuffix.add("md");
    }

    public static void main(String[] args) throws IOException {
        long startTime = System.currentTimeMillis();
        String path = "F:\\blog_doc\\Blog document";
        //1. Read all video files in the folder
        List<File> fileList = new ArrayList<>();
        readFileInDir(path, fileList);
        List<String> fileNameList = fileList.stream().map(File::getName).collect(Collectors.toList());
        log.info("The resulting file list is:");
        fileNameList.stream().forEach(t -> System.out.println(t));
        log.info("The number of files to be converted is:{}",fileNameList.size());
        String toRegexStr = "E{1}\\:\\\\blogPic\\b";
        String toReplaceStr = "F:\\\\blog_doc\\\\blogPic";
        fileList.stream().forEach(t -> replaceImgPath(t, toRegexStr, toReplaceStr));
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        log.info("Batch file string replacement completed, number of original files:{},Total replacement strings:{}, total time:{}ms",fileNameList.size(),count,costTime);
    }

    /**
     * Recursively read all files in the folder
     *
     * @param path
     */
    public static void readFileInDir(String path, List<File> fileList) {
        File f = new File(path);
        //Get all files under the file
        File[] files = f.listFiles();

        for (File file : files) {
            if (file.isDirectory()) {
                readFileInDir(file.getAbsolutePath(), fileList);
            } else {
                if (isMarkDownFile(file.getName())) {
                    fileList.add(file);
                }
            }
        }
    }

    /**
     * Determine whether it is a markdown document
     *
     * @param fileName
     * @return
     */
    public static boolean isMarkDownFile(String fileName) {
        boolean result = false;
        String suffix = fileName.substring(fileName.lastIndexOf('.') + 1);
        if (markDownFileSuffix.contains(suffix)) {
            result = true;
        }
        return result;
    }

    /**
     * Start replacing contents in file
     * @param sourceFile source file
     * @param targetRegex A matching regular expression is required
     * @param toReplaceStr String to replace with
     */
    public static void replaceImgPath(File sourceFile, String targetRegex, String toReplaceStr) {
        String regex = targetRegex;
        String targetFileDir = "F:\\Blog document_new";//The target folder and processed files will be written to this folder, and the classification will be guaranteed according to the original file path
        BufferedReader reader = null;
        BufferedWriter writer = null;
        log.info("Start processing file:{},The final file will exist in the directory:{}in",sourceFile.getAbsoluteFile(),targetFileDir);
        String fileName = sourceFile.getAbsoluteFile() + "/" + sourceFile.getName();
        try {
            //Construct source file reader
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile)));
            //Create target file
            File targetFile = createTargetFile(sourceFile,targetFileDir);
            if(null == targetFile){
                log.info("file:{},Failed to create target file, please operate manually",sourceFile.getAbsolutePath());
                return;
            }
            //Construct target file writer
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile)));
            String tempStr = "";
            String regStr = regex;
            Pattern pattern = Pattern.compile(regStr);
            while ((tempStr = reader.readLine()) != null) {
                tempStr += "\n"; //Add line breaks to avoid formatting confusion
                Matcher matcher = pattern.matcher(tempStr);
                if (matcher.find()) {//If it matches, replace it
                    //Replace as specified
                    tempStr = tempStr.replaceAll(regex, toReplaceStr);
                    log.info("file:{},The replaced string is:{}",sourceFile.getAbsoluteFile(), tempStr);
                    count++;
                }
                writer.write(tempStr);
            }
            writer.flush();
        } catch (Exception e) {
            //Record exception
            log.error("file:{},Character replacement exception. The exception information is:{},Please operate manually", fileName,e);
            return;
        } finally {
            //Close flow
            try {
                reader.close();
            } catch (IOException e) {
                log.error("file:{},Flow closing exception", fileName);
            }
            try {
                writer.close();
            } catch (IOException e) {
                log.error("file:{},Flow closing exception", fileName);
            }
        }
    }

    /**
     * Create the target file according to the original file path
     * @param sourceFile source file
     * @param targetFileDir Destination file root path
     * @return
     */
    public static File createTargetFile(File sourceFile,String targetFileDir){
        //Get absolute path of source file
        String sourceFileAbsoluteName = sourceFile.getAbsolutePath();
        String afterDealFileName = sourceFileAbsoluteName.replace("F:\\blog_doc", targetFileDir);
        //Intercept the folder path and file name
        int splitIndex = afterDealFileName.lastIndexOf("\\");
        //Folder path
        String dirPath = afterDealFileName.substring(0,splitIndex+1);
        //file name
        String createFileName = afterDealFileName.substring(splitIndex+1);
        log.info("The target file name to be created is:{},Exist in:{}folder",createFileName,dirPath);
        //Create folder recursively first
        File dirFile = new File(dirPath);
        if(!dirFile.exists()){
            dirFile.mkdirs();
            log.info("folder:{}Creation complete",dirPath);
        }
        //Create target file
        File targetFile = new File(dirPath,createFileName);
        if(!targetFile.exists()){
            try {
                targetFile.createNewFile();
            } catch (IOException e) {
                log.error("file:{}Create exception:{}",targetFile.getAbsolutePath(),e);
                return null;
            }
            log.info("file:{}Creation complete",targetFile.getAbsolutePath());
        }
        //Returns the created file
        return targetFile;
    }
}

The complete code has been posted, and the operation is as follows

153 documents, 1049 replacements, 506 MS

summary

A simple markdown text replacement tool

Posted by Chesso on Mon, 08 Nov 2021 00:07:45 -0800