com.github.siwenyan.dish_parser.SyntaxSimple Maven / Gradle / Ivy
package com.github.siwenyan.dish_parser;
import com.github.siwenyan.common.StringTools;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SyntaxSimple {
// Symbols
public static final String SYMBOL_COMMENT = "//";
public static final String SYMBOL_BLOCK_BEGIN = "{";
public static final String SYMBOL_BLOCK_END = "}";
public static final String SYMBOL_QUOTE = "\"";
public static final String SYMBOL_SQUOTE = "'";
public static final String SYMBOL_DELICIOUS = "!";
public static final String SYMBOL_EQUAL = "=";
public static final String[] WHITE_SPACES = new String[] { " ", "\t", "\r", "\n" };
// Reserved var prefixes
public static final String RESERVED_VAR_PREFIX_THIS_DOT = "this.";
public static final String[] RESERVED_VAR_PREFIXES = new String[] { RESERVED_VAR_PREFIX_THIS_DOT };
public static final boolean isReservedVarName(String varName) {
if (varName == null || varName.trim().isEmpty()) {
return true;
}
varName = varName.trim();
for (String prefix : RESERVED_VAR_PREFIXES) {
if (varName.startsWith(prefix)) {
return true;
}
}
return false;
}
public static Map buildMap(String params, String d0, String d1) {
Map p = new HashMap(0);
if (null == params || params.trim().isEmpty()) {
return p;
}
if (!params.isEmpty()) {
List pairs = splitWithQuotedString(params, SyntaxSimple.SYMBOL_SQUOTE, new String[]{d0},
Integer.MAX_VALUE, false, null);
for (String keyValuePair : pairs) {
List pair = splitWithQuotedString(keyValuePair, SyntaxSimple.SYMBOL_SQUOTE,
new String[]{d1}, 2, true, null);
if (2 != pair.size()) {
if (1 == pair.size()) {
p.put(pair.get(0), "");
continue;
} else {
return null;
}
}
String key = pair.get(0).trim();
String value = pair.get(1).trim();
p.put(key, value);
}
}
return p;
}
// Reserved var names
public static final String RESERVED_TABLE_NAME = "tableName";
public static final String RESERVED_START_DATE_ISO = "startDateIso";
// Regex Strings
// public static final String REGEX_COMMENT_BLOCK =
// "\\/\\*(\\*(?!\\/)|[^*])*\\*\\/";
public static final String REGEX_BLOCK = "^\\s*\\{([^\"]*\"[^\"]*\")*[^\"]*\\}\\s*$";
public static final String REGEX_BLOCK_BEGIN = "^\\s*\\{.*";
public static final String REGEX_BLOCK_END = "^.*\\}\\s*";
public static final String REGEX_COMMENT_LINE = "^\\s*\\{?\\s*//.*";
public static final String REGEX_WORD = "[_%A-Za-z0-9]+";
public static final String REGEX_NUMBER = "0|[1-9][0-9]*";
public static final String REGEX_FLAVOR = ""
// [!flavor@tableName#99]
+ "\\s*" // possible spaces in the beginning
+ "(" + SYMBOL_DELICIOUS + ")?" // optional group 1: [!]
+ "(" + REGEX_WORD + ")" // required group 2: [flavor]
+ "(@(" + REGEX_WORD + "))?" // optional group 4: [tableName]
+ "(#(" + REGEX_NUMBER + "))?"; // optional group 6: [99]
public static final String REGEX_SENTENCE = ""
// [!flavor@tableName#99 key1=value1 key2=%value2% key3=va%lue%3]
+ "^" // matches the beginning of the string
+ REGEX_FLAVOR // starts with a flavor
+ "\\s*(.*)" // optional group 7: [key1=value1 key2=%value2%
// key3=va%lue%3]
+ "$";// matches the ending of the string
public static final String REGEX_SPLIT_SENTENCES = "\\s*;\\s*(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
public static final String REGEX_SPLIT_FLAVOR = "\\s+(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
public static final String REGEX_SPLIT_PARAMS = "\\s+(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
public static final String REGEX_SPLIT_KEY_VALUE = "=(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
public static final String REGEX_MATCH_NORM_PATAMS = "(\\s*X\\s*)?((\\s*X\\s*)=(\\s*X\\s*))*";
public static final String NORM_TEXT_PLACEHOLDER = "X";
// debug mode
public static final String GO_IN = "in";
public static final String GO_OUT = "out";
// Prebuild Patterns
public static final Pattern PATTERN_MATCH_NORM_PATAMS = Pattern.compile(REGEX_MATCH_NORM_PATAMS);
public static final Pattern PATTERN_FLAVOR = Pattern.compile(REGEX_FLAVOR);
public static void main(String[] args) throws BadSmellException {
String[] tests = new String[] { "flavor1", "!flavor2", "flavor3@tableName", "flavor4#23", "!flavor@tableName#99" };
for (String test : tests) {
Matcher matcher = PATTERN_FLAVOR.matcher(test);
// System.out.println(test);
while (matcher.find()) {
for (int i = 0; i < matcher.groupCount() + 1; i++) {
String s = matcher.group(i);
System.out.println(i + ": [" + s + "]");
}
}
}
// expected: "AC*/DG*/HK"
System.out.println(removeCommentBlocks("/*0\r\n00*/A/*B*/C*/D/*E/*F*/G*/H/*I\r\nJ*/K"));
}
public static String scanBlock(Scanner scanner) throws BadSmellException {
StringBuilder stringBuilder = new StringBuilder();
String text = "";
while (scanner.hasNextLine()) {
String line = scanNextLineIgnoreCommentOrEmptyLines(scanner);
if (!line.isEmpty()) {
stringBuilder.append(" ");
stringBuilder.append(line);
text = stringBuilder.toString();
if (text.matches(REGEX_BLOCK_BEGIN)) {
if (text.matches(REGEX_BLOCK)) {
break;
}
} else {
break;
}
}
}
// ".../*...*/... " --> "......"
text = removeCommentBlocks(text);
if (text.matches(REGEX_BLOCK_BEGIN)) {
if (text.matches(REGEX_BLOCK)) {
// " {...}" --> "..."
text = text.substring(1, text.length() - 1);
} else {
throw new BadSmellException("Syntax error: missing end brace of '}'.");
}
}
text = text.trim();
int count = count(text, SYMBOL_QUOTE);
if (count % 2 == 1) {
throw new BadSmellException("Syntax error: quote mismatches.");
}
return text;
}
public static List splitSentences(String text) throws BadSmellException {
if (text == null) {
return null;
}
int count = count(text, SYMBOL_QUOTE);
if (count % 2 == 1) {
throw new BadSmellException("Syntax error: quote mismatches.");
}
String[] lines = text.split(REGEX_SPLIT_SENTENCES);
List validLines = new ArrayList(lines.length);
for (String line : lines) {
if (line.trim().isEmpty() || line.startsWith(SYMBOL_COMMENT)) {
// skip empty/comment lines
continue;
} else {
if (line.matches(REGEX_SENTENCE)) {
validLines.add(line);
} else {
throw new BadSmellException("Syntax error: " + line);
}
}
}
return validLines;
}
private static int count(String text, String regex) {
if (text == null || regex == null) {
return -1;
}
int count = 0;
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
count++;
}
return count;
}
private static String scanNextLineIgnoreCommentOrEmptyLines(Scanner scanner) {
String line = scanner.nextLine().trim();
if (line == null || line.isEmpty() || line.matches(REGEX_COMMENT_LINE)) {
if (line.startsWith(SYMBOL_BLOCK_BEGIN)) {
return SYMBOL_BLOCK_BEGIN;
} else if (line.matches(REGEX_BLOCK_END)) {
return SYMBOL_BLOCK_END;
} else {
return "";
}
} else {
return line;
}
}
public static String[] slideFlavor(String text) {
return text.trim().split(REGEX_SPLIT_FLAVOR, 2);
}
public static String replaceGroup(String regex, String source, int groupToReplace, int groupOccurrence,
String replacement) {
Matcher m = Pattern.compile(regex).matcher(source);
for (int i = 0; i < groupOccurrence; i++)
if (!m.find())
// pattern not met, may also throw an exception here
return source;
return new StringBuilder(source).replace(m.start(groupToReplace), m.end(groupToReplace), replacement)
.toString();
}
public static String replaceFlavor(String line, Flavor.FlavorPart flavorPart, String replacement)
throws BadSmellException {
if (line == null || line.trim().isEmpty() || flavorPart == null) {
throw new BadSmellException("Invalid Parameters.");
}
line = line.trim();
replacement = replacement == null ? "" : replacement.trim();
String[] parts = SyntaxSimple.slideFlavor(line);
parts[0] = parts[0].trim();
if (parts.length == 2) {
parts[1] = parts[1].trim();
}
switch (flavorPart) {
case TABLE_NAME:
if (replacement.isEmpty()) {
parts[0] = parts[0].replaceAll("[@](" + REGEX_WORD + ")", "");
} else {
if (!replacement.matches(REGEX_WORD)) {
throw new BadSmellException("Invalid tableName.");
}
parts[0] = parts[0].replaceAll("[@](" + REGEX_WORD + ")", "@" + replacement);
}
break;
case CUT_IN_AT:
if (replacement.isEmpty()) {
parts[0] = parts[0].replaceAll("[#](" + REGEX_NUMBER + ")", "");
} else {
if (!replacement.matches(REGEX_NUMBER)) {
throw new BadSmellException("Invalid cutInAt.");
}
parts[0] = parts[0].replaceAll("[#](" + REGEX_NUMBER + ")", "[#]" + replacement);
}
break;
case IS_DELICIOUS:
if (replacement.isEmpty()) {
if (parts[0].startsWith("!")) {
parts[0] = parts[0].substring(1);
}
} else if ("!".equals(replacement)) {
if (!parts[0].startsWith("!")) {
parts[0] = "!" + parts[0];
}
} else {
throw new BadSmellException("Invalid isDelicious.");
}
break;
default:
throw new BadSmellException("Invalid flavorPart.");
}
if (parts.length == 1) {
return parts[0];
} else {
return parts[0] + " " + parts[1];
}
}
public static void removeReservedParameters(IDish dish) {
for (String key : Constants.RESERVED_PARAMETERS) {
dish.removeElement(key);
}
List keys = new ArrayList(dish.size());
for (String key : Constants.RESERVED_PARAMETER_PARTS) {
keys.addAll(dish.getElementKeySet(key));
}
for (String key : keys) {
dish.removeElement(key);
}
}
public static String removeCommentBlocks(String raw) {
if (raw == null || raw.trim().isEmpty()) {
return "";
}
String quote = "\"";
StringBuilder sb = new StringBuilder();
boolean quoted = false;
int pos = 0;
char[] rawChars = raw.toCharArray();
while (pos < rawChars.length) {
if (match(rawChars, pos, quote)) {
quoted = !quoted;
sb.append(quote);
pos += quote.length();
} else {
if (quoted) {
sb.append(rawChars[pos++]);
} else {
if (match(rawChars, pos, "/*")) {
List test = splitWithQuotedString(raw.substring(pos), quote,
new String[] { "*/" }, 2, true, null);
if (test.size() > 1) {
raw = test.get(1);
pos = 0;
rawChars = raw.toCharArray();
}
} else {
sb.append(rawChars[pos++]);
}
}
}
}
return sb.toString().trim();
}
public static List splitWithQuotedString(String raw, String quote, String[] splitters, int limit,
boolean peel, StringNorm norm) {
List result = new ArrayList();
StringBuilder sb = new StringBuilder();
boolean quoted = false;
int pos = 0;
char[] rawChars = raw.toCharArray();
while (pos < rawChars.length) {
if (match(rawChars, pos, quote)) {
quoted = !quoted;
sb.append(quote);
pos += quote.length();
} else {
if (quoted) {
sb.append(rawChars[pos++]);
} else {
String splitter = null;
for (String str : splitters) {
if (match(rawChars, pos, str)) {
splitter = str;
break;
}
}
if (splitter != null) {
String str = sb.toString();
if (!str.isEmpty()) {
str = peel ? StringTools.peel(str, quote) : str;
result.add(str);
if (norm != null) {
norm.append(norm.getTextPlaceholder());
}
}
sb.setLength(0);
if (norm != null) {
norm.append(splitter);
}
pos += splitter.length();
if (result.size() + 1 == limit) {
String str1 = raw.substring(pos);
str1 = peel ? StringTools.peel(str1, quote) : str1;
result.add(str1);
if (norm != null) {
norm.append(norm.getTextPlaceholder());
}
return result;
}
} else {
sb.append(rawChars[pos++]);
}
}
}
}
String str = sb.toString();
str = peel ? StringTools.peel(str, quote) : str;
result.add(str);
if (norm != null && !str.isEmpty()) {
norm.append(norm.getTextPlaceholder());
}
return result;
}
public static boolean match(char[] rawChars, int pos, String quote) {
String test = new String(Arrays.copyOfRange(rawChars, pos, pos + quote.length()));
return test.equals(quote);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy