Skip to content

Instantly share code, notes, and snippets.

@techyourchance
Last active August 14, 2023 17:08
Show Gist options
  • Save techyourchance/dc764f11ee7af6ce823a18fe5b340df9 to your computer and use it in GitHub Desktop.
Save techyourchance/dc764f11ee7af6ce823a18fe5b340df9 to your computer and use it in GitHub Desktop.
Script that refactors Java and Kotlin files from mHungarianNotation to camelCase
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class HungarianRemover {
private enum SupportedLanguage {
JAVA, KOTLIN
}
private static final String IDENTIFIER_CHAR_REGEXP = "[a-zA-Z0-9_]"; // intentionally omitted $
private static final String HUNGARIAN_FIRST_CHAR_REGEXP = "[ms]";
private static final String HUNGARIAN_IDENTIFIER_REGEXP = ""
+ "(?<!" + IDENTIFIER_CHAR_REGEXP + ")" // not preceeded by a valid identifier char
+ HUNGARIAN_FIRST_CHAR_REGEXP // one of "hungarian" first chars
+ "([A-Z])" // followed by a capital letter
+ "(" + IDENTIFIER_CHAR_REGEXP + "{2,})"; // followed by at least two more chars
private static final String JAVA_SIMPLE_ASSIGNMENT_REGEXP = ""
+ "^(\\s*)" // only preceeding whitespaces
+ "(" + IDENTIFIER_CHAR_REGEXP + "+)" // identifier
+ "(\\s*=\\s*)" // equals
+ "(" + IDENTIFIER_CHAR_REGEXP + "+)" // identifier
+ "(\\s*;)"; // trailing semicolon
public static void main(String[] args) {
File targetDir;
try {
targetDir = extractTargetDirFromArgs(args);
} catch (Exception e) {
error(e.getMessage());
return;
}
print("Target directory: " + targetDir.toString());
HungarianRemover remover = new HungarianRemover();
try {
remover.removeHungarianNotationInDir(targetDir);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static File extractTargetDirFromArgs(String[] args) throws Exception {
Path path;
if (args.length == 0) {
path = Paths.get(".").toAbsolutePath();
} else {
path = Paths.get(args[0]).toAbsolutePath();
}
if (Files.exists(path) && Files.isDirectory(path)) {
return path.toFile();
} else {
throw new Exception("Directory doesn't exist: " + path.toString());
}
}
private static void print(String message) {
System.out.println(message);
}
private static void error(String message) {
System.out.println("Error! " + message);
}
private int linesChanged = 0;
private int identifiersChanged = 0;
public void removeHungarianNotationInDir(File targetDir) throws Exception {
Collection<File> files = getAllRelevantFilesInDir(targetDir);
for (File file : files) {
removeHungarianNotationInFile(file);
}
print("Done");
print("Lines changed: " + linesChanged);
print("Identifiers changed: " + identifiersChanged);
}
public Collection<File> getAllRelevantFilesInDir(File dir) {
Collection<File> fileTree = getAllFilesInDir(dir);
return fileTree.stream()
.filter(file -> {
String absolutePath = file.getAbsolutePath();
return (absolutePath.endsWith(".java") || absolutePath.endsWith(".kt"))
&& !absolutePath.contains(".git")
&& !absolutePath.contains(".orig");
})
.collect(Collectors.toList());
}
public Collection<File> getAllFilesInDir(File dir) {
Set<File> fileTree = new HashSet<>();
if (dir == null || dir.listFiles() == null) {
return fileTree;
}
for (File entry : dir.listFiles()) {
if (entry.isFile()) {
fileTree.add(entry);
} else {
fileTree.addAll(getAllRelevantFilesInDir(entry));
}
}
return fileTree;
}
public void removeHungarianNotationInFile(File file) throws Exception {
SupportedLanguage language = deriveLanguageFromExtension(file);
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
StringBuilder editedLines = new StringBuilder();
String originalLine;
String editedLine;
while ((originalLine = bufferedReader.readLine()) != null) {
editedLine = removeHungarianNotationInLine(originalLine);
if (language == SupportedLanguage.JAVA) {
editedLine = correctSameNameClassFieldAssignmentsInJava(editedLine);
}
if (!editedLine.equals(originalLine)) {
linesChanged++;
}
editedLines.append(editedLine);
editedLines.append("\n");
}
FileWriter fw = new FileWriter(file, false);
fw.append(editedLines.toString());
fw.close();
}
public SupportedLanguage deriveLanguageFromExtension(File file) {
if (file.getName().endsWith(".java")) {
return SupportedLanguage.JAVA;
} else if (file.getName().endsWith(".kt")) {
return SupportedLanguage.KOTLIN;
} else {
throw new RuntimeException("Unsupported file extension: " + file.getName());
}
}
public String removeHungarianNotationInLine(String line) {
return Pattern.compile(HUNGARIAN_IDENTIFIER_REGEXP)
.matcher(line)
.replaceAll(m -> {
identifiersChanged++;
return m.group(1).toLowerCase() + m.group(2);
});
}
public String correctSameNameClassFieldAssignmentsInJava(String line) {
return Pattern.compile(JAVA_SIMPLE_ASSIGNMENT_REGEXP)
.matcher(line)
.replaceAll(m -> {
if (m.group(2).equals(m.group(4))) { // if identifiers on both sides of "=" are the same
return m.group(1) + "this." + m.group(2) + m.group(3) + m.group(4) + m.group(5);
} else {
return m.group(0); // no change
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment