All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.siwenyan.dish_parser.SyntaxSimple Maven / Gradle / Ivy

There is a newer version: 1.25
Show newest version
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