1 /* 2 * hunt-console eases the creation of beautiful and testable command line interfaces. 3 * 4 * Copyright (C) 2018-2019, HuntLabs 5 * 6 * Website: https://www.huntlabs.net 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.console.input.StringInput; 13 14 import hunt.console.error.InvalidArgumentException; 15 import hunt.console.util.StringUtils; 16 17 import hunt.collection.ArrayList; 18 import hunt.collection.List; 19 import hunt.console.input.ArgvInput; 20 import hunt.text.Common; 21 import std.string; 22 import std.regex; 23 24 class StringInput : ArgvInput 25 { 26 private static string REGEX_STRING = "([^\\s]+?)(?:\\s|(?<!\\\\\\\\)\"|(?<!\\\\\\\\)\\'|$)"; 27 28 private static string REGEX_QUOTED_STRING = "(?:\"([^\"\\\\\\\\]*(?:\\\\\\\\.[^\"\\\\\\\\]*)*)\"|\\'([^\\'\\\\\\\\]*(?:\\\\\\\\.[^\\'\\\\\\\\]*)*)\\')"; 29 30 public this(string input) 31 { 32 super(null); 33 34 setTokens(tokenize(input)); 35 } 36 37 private List!(string) tokenize(string input) 38 { 39 List!(string) tokens = new ArrayList!(string)(); 40 int length = cast(int)(input.length); 41 string inputPart; 42 string token; 43 int matchLength; 44 int cursor = 0; 45 46 string whiteSpace = /* Pattern.compile */("^\\s+"); 47 // Matcher whiteSpaceMatcher; 48 string quotedOption = /* Pattern.compile */("^([^=\"\\'\\s]+?)(=?)(" ~ REGEX_QUOTED_STRING ~ "+)"); 49 // Matcher quotedOptionMatcher; 50 string quotedstring = /* Pattern.compile */("^" ~ REGEX_QUOTED_STRING); 51 // Matcher quotedStringMatcher; 52 string str = /* Pattern.compile */("^" ~ REGEX_STRING); 53 // Matcher stringMatcher; 54 55 while (cursor < length) { 56 57 inputPart = input.substring(cursor); 58 59 auto whiteSpaceMatcher =matchAll(inputPart, whiteSpace); 60 auto quotedOptionMatcher = matchAll(inputPart,quotedOption); 61 auto quotedStringMatcher = matchAll(inputPart,quotedstring); 62 auto stringMatcher = matchAll(inputPart,str); 63 64 if (!whiteSpaceMatcher.empty()) { 65 matchLength = cast(int)(whiteSpaceMatcher.front().captures[0].length); 66 } else if (!quotedOptionMatcher.empty()) { 67 token = quotedOptionMatcher.front().captures[1] ~ quotedOptionMatcher.front().captures[2] ~ StringUtils.unquote(quotedOptionMatcher.front().captures[3].substring(1, quotedOptionMatcher.front().captures[3].length - 1).replace("(\"')|('\")|('')|(\"\")", "")); 68 tokens.add(token); 69 matchLength = cast(int)(quotedOptionMatcher.front().captures[0].length); 70 } else if (!quotedStringMatcher.empty()) { 71 token = quotedStringMatcher.front().captures[0]; 72 tokens.add(StringUtils.unquote(token.substring(1, token.length - 1))); 73 matchLength = cast(int)(token.length); 74 } else if (!stringMatcher.empty()) { 75 token = stringMatcher.front().captures[1]; 76 tokens.add(StringUtils.unquote(token)); 77 matchLength = cast(int)(stringMatcher.front().captures[0].length); 78 } else { 79 // should never happen 80 throw new InvalidArgumentException(format("Unable to parse input near '... %s ...", input.substring(cursor, cursor + 10))); 81 } 82 83 cursor += matchLength; 84 } 85 86 return tokens; 87 } 88 }