作者:ChenZhen
本人不常看网站消息,有问题通过下面的方式联系:
- 邮箱:1583296383@qq.com
- vx: ChenZhen_7
我的个人博客地址:https://www.chenzhen.space/🌐
版权:本文为博主的原创文章,本文版权归作者所有,转载请附上原文出处链接及本声明。📝
如果对你有帮助,请给一个小小的star⭐🙏
概要
这段Java代码用于自动更新源代码文件中的创建者信息(作者信息)以及注释。它的主要功能包括:
-
遍历指定目录下的Java文件:通过指定的项目路径,递归地处理目录下的所有Java文件。
-
更新创建者信息:针对每个Java文件,它会寻找最后一个
import
语句和public class
或public interface
等(即类的声明语句)之间的位置,在此处尝试定位文件的开头,并且会在文件的开头插入作者信息。 -
检测和处理注释:程序会检查文件中是否包含注释,如果存在注释,则会检查其中是否已包含作者信息,如果没有,则在注释中的合适位置插入新的作者信息,如果已经存在作者信息,则替换为新的作者信息。
-
输出比较结果:在更新作者信息后,会输出部分的原始内容与更新后内容的比较结果,通过高亮显示差异部分,以便用户检查更改,不满意可跳过处理。
-
文件写回:按回车更新,完成后,会将修改后的内容写回到相应的Java文件中。
总体来说,这段代码的主要目的是自动化处理Java文件中的创建者信息,确保每个文件都有统一的作者信息,并提供了对比功能,让用户可以直观地看到更改的部分。
运行截图:
控制台会显示import
语句和类的声明之间的位置的代码,左边是代码修改前的,右边是代码修改后,修改过的内容会通过红色高亮显示。
代码:
首先,指定项目路径;其次,输入作者名;然后运行即可。
package com.example.demo1;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class CreatorInfoUpdater {
public static void main(String[] args) throws IOException {
// 指定项目路径
String directoryPath = "D:\\project\\新建文件夹\\demo1\\src\\main\\java\\com\\example\\demo1";
// 指定你的作者名
String author = "chenzhen";
// 处理文件
File directory = new File(directoryPath);
// 判断目录是否存在
if (directory.exists() && directory.isDirectory()) {
processFiles(directory,author);
} else {
System.out.println("Invalid directory path");
}
Scanner scanner = new Scanner(System.in);
scanner.close();
}
/**
* 给文件添加创建者信息
* 检查文件中是否包含注释,如果存在注释,则会检查其中是否已包含作者信息
* 如果有:则换成新的作者
* 如果没有:则在注释中的合适位置插入新的作者信息。
* @param file
* @throws IOException
*/
private static void insertCreatorInfo(File file,String author) throws IOException {
Scanner scanner = new Scanner(System.in);
String creatorInfo =
"/**\n" +
" * @author "+ author + "\n" +
" */";
// 读取文件内容
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
StringBuilder content = new StringBuilder();
// 逐行读取文件内容并保存到StringBuilder中
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
reader.close();
int start = -1;
int end = -1;
//创建正则表达式模式,匹配最后一个import语句
Pattern pattern = Pattern.compile("import\\s+[^;]+;");
Matcher matcher = pattern.matcher(content);
int importOrPackStartIdx = -1;
int importOrPackEndIdx = -1;
// 找到最后一个匹配的import语句
while (matcher.find()) {
importOrPackStartIdx = matcher.start();
importOrPackEndIdx = matcher.end();
}
if (importOrPackStartIdx == -1 || importOrPackEndIdx == -1) {
//创建正则表达式模式,匹配package语句
Pattern packPattern = Pattern.compile("package\\s+[^;]+;");
Matcher packMatcher = packPattern.matcher(content);
if (!packMatcher.find()) {
System.err.println("未找到import或package语句 文件:" + file.getAbsolutePath() );
System.out.println("输入任意键继续:");
scanner.nextLine();
return;
}
importOrPackStartIdx = packMatcher.start();
importOrPackEndIdx = packMatcher.end();
}
String codeAfterImport = content.substring(importOrPackEndIdx);
start = importOrPackEndIdx;
// 创建正则表达式模式,匹配public class或public interface
Pattern classInterfacePattern = Pattern.compile("(?<!\\S)(public\\s+(class|interface|enum|abstract|@interface))\\b");
Matcher classInterfaceMatcher = classInterfacePattern.matcher(codeAfterImport);
int classInterfaceStartIdx = -1;
int classInterfaceEndIdx = -1;
// 找到匹配的public class或public interface
if (classInterfaceMatcher.find()) {
classInterfaceStartIdx = importOrPackEndIdx + classInterfaceMatcher.start();
classInterfaceEndIdx = importOrPackEndIdx + classInterfaceMatcher.end();
}
if (classInterfaceStartIdx == -1 || classInterfaceEndIdx == -1) {
;
System.err.println("未找到匹配的public class或public interface 文件:" + file.getAbsolutePath());
System.out.println("输入任意键继续:");
scanner.nextLine();
return;
}
String betweenImportAndClass = content.substring(importOrPackEndIdx, classInterfaceStartIdx);
// 创建正则表达式模式,匹配多行注释
Pattern commentPattern = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
Matcher commentMatcher = commentPattern.matcher(betweenImportAndClass);
StringBuffer buffer = new StringBuffer();
boolean hasComment = false;
// */的偏移量
int insertionIndex = 0;
//如果已经有注释了
if (commentMatcher.find()) {
// 获取注释
String comment = commentMatcher.group();
// 创建正则表达式模式,匹配多行注释中的现有的作者信息
Pattern authorPattern = Pattern.compile("(@author|@author:)\\s+[^\\n]+");
Matcher authorMatcher = authorPattern.matcher(comment);
StringBuffer authorBuffer = new StringBuffer();
insertionIndex = comment.indexOf("*/");
//如果注释中已经有其他的@author作者信息,统一替换
if (authorMatcher.find()) {
System.out.println("注释中已经有其他的创建者信息" + authorMatcher.group());
authorMatcher.appendReplacement(authorBuffer, "@author " + author);
authorMatcher.appendTail(authorBuffer);
creatorInfo = authorBuffer.toString();
}else{
// 如果没有则在注释中间找到一个适当的位置插入作者信息
String updatedComment = new StringBuilder(comment)
.insert(insertionIndex, "* @author " + author + "\n ")
.toString();
commentMatcher.appendReplacement(buffer, updatedComment);
//更正创建者信息
creatorInfo = buffer.toString();
}
hasComment = true;
}
String betweenCommendAndClass = "";
int commentEndIdx = importOrPackEndIdx;
// 如果存在注释
if (hasComment){
commentEndIdx += insertionIndex + 4;
}
betweenCommendAndClass = content.substring(commentEndIdx, classInterfaceStartIdx);
// 创建正则表达式模式,匹配注解
Pattern annotationPattern = Pattern.compile("(?<=^|\\s)@\\w+(?![\\w\\s]*\\*/)");
Matcher annotationMatcher = annotationPattern.matcher(betweenCommendAndClass);
int annotationStartIdx = -1;
int annotationEndIdx = -1;
// 找到第一个匹配的注解
if (annotationMatcher.find()) {
annotationStartIdx = commentEndIdx + annotationMatcher.start();
annotationEndIdx = commentEndIdx + annotationMatcher.end();
}
if (annotationStartIdx == -1 || annotationEndIdx == -1) {
System.out.println("未找到匹配的注解");
end = classInterfaceStartIdx - 1;
}else{
end = annotationStartIdx - 1;
}
String updateContent;
creatorInfo = Arrays.stream(creatorInfo.split("\n"))
.filter(item -> !item.trim().equals("*"))
.collect(Collectors.joining("\n"));
// 获取要替换的部分之前的字符串
String partBefore = content.substring(0, start);
// 获取要替换的部分之后的字符串
String partAfter = content.substring(end); // 加1是为了不包含 endIndex 这个位置的字符
// 组合新的字符串
updateContent = partBefore + "\n\n" + creatorInfo + partAfter;
Matcher newClassInterfaceMatcher = classInterfacePattern.matcher(updateContent);
if (newClassInterfaceMatcher.find()) {
int newClassInterfaceEndIdx = newClassInterfaceMatcher.end();
printAandB(content.substring(importOrPackStartIdx,classInterfaceEndIdx), updateContent.substring(importOrPackStartIdx,newClassInterfaceEndIdx));
}else {
System.err.println("未找到新的匹配的public class或public interface 文件:" + file.getAbsolutePath());
System.out.println(content.substring(importOrPackStartIdx,classInterfaceEndIdx));
System.out.println("输入任意键继续:");
scanner.nextLine();
return;
}
System.out.println("回车添加创建者信息,或者输入 'n' 跳过,");
System.out.println("文件 = " + file.getAbsolutePath());
String input = scanner.nextLine();
if (input.equals("n")) {
return;
}
// 写回到文件中
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.write(updateContent);
writer.close();
}
/**
* 递归处理给定目录下的所有文件,为所有的 Java 文件插入创建者信息。
*
* @param directory 要处理的目录
* @throws IOException 如果发生 I/O 错误时抛出异常
*/
private static void processFiles(File directory,String author) {
// 获取目录下的所有文件
File[] files = directory.listFiles();
if (files == null){
System.out.println("文件为空");
return;
}
for (File file : files) {
// 如果是目录,则递归处理子目录
if (file.isDirectory()) {
processFiles(file,author);
} else if (file.getName().endsWith(".java")) {
try {
// 插入创建者信息到 Java 文件中
insertCreatorInfo(file,author);
System.out.println("\n\n");
} catch (Exception e) {
// 打印异常信息和出错文件的路径
e.printStackTrace();
System.err.println("文件出错 = " + file.getAbsolutePath());
}
}
}
}
/**
* 将两个字符串按行比较并打印输出,标记相同行和不同行。
*
* @param stringA 第一个字符串
* @param stringB 第二个字符串
*/
public static void printAandB(String stringA, String stringB) {
// 按行分割两个字符串
String[] linesA = stringA.split("\n");
String[] linesB = stringB.split("\n");
// 获取两个字符串中最大行数和最大行长度
int maxLineLength = Math.max(linesA.length, linesB.length);
int maxStringLength = 0;
for (int i = 0; i < maxLineLength; i++) {
String lineA = (i < linesA.length) ? linesA[i] : "";
String lineB = (i < linesB.length) ? linesB[i] : "";
int tempMax = Math.max(lineA.length(), lineB.length());
maxStringLength = Math.max(maxStringLength, tempMax);
}
// 保存相同行的列表
ArrayList<String> highlightList = new ArrayList<>();
// 找出相同的行并加入到相同行的列表中
for (int i = 0; i < maxLineLength; i++){
String lineA = (i < linesA.length) ? linesA[i]: "";
for (int j = 0; j < maxLineLength; j++) {
String lineB = (j < linesB.length) ? linesB[j] : "";
if (lineA.equals(lineB)) {
highlightList.add(lineA);
}
}
}
System.out.println("\n");
// 打印并标记相同和不同的行
for (int i = 0; i < maxLineLength; i++) {
String lineA = (i < linesA.length) ? linesA[i] : "";
String lineB = (i < linesB.length) ? linesB[i] : "";
StringBuilder lineAbuilder = new StringBuilder(lineA);
while (lineAbuilder.length() < maxStringLength) {
lineAbuilder.append(" ");
}
String finalLineA = lineAbuilder.toString().replaceAll("[\\u4E00-\\u9FFF]", "x");
if (highlightList.contains(lineA)) {
System.out.print(finalLineA);
} else {
// 如果比较内容不同,在控制台输出时标记为红色
System.out.print("\033[31m" + finalLineA.substring(0,lineA.length()) + "\033[0m" + finalLineA.substring(lineA.length()));
}
System.out.print(" =\t");
if (highlightList.contains(lineB)) {
System.out.println(lineB);
} else {
// 如果比较内容不同,在控制台输出时标记为红色
System.out.println("\033[31m" + lineB + "\033[0m");
}
}
System.out.println("\n");
}
}