1 module jcli.core.pattern; 2 3 struct Pattern 4 { 5 import std.ascii; 6 import std.algorithm; 7 8 string[] items; 9 alias items this; 10 11 this(string[] items) @safe pure nothrow 12 in 13 { 14 assert(items.length > 0, "The pattern must contain at least one item."); 15 assert(items.all!(i => i.all!isASCII), "The pattern items must be ascii."); 16 assert(items.all!(i => i.length > 0), "The pattern must not contain empty items."); 17 assert(items.map!(i => i.length).maxIndex == 0, "The first item in the items list must be the longest"); 18 } 19 do 20 { 21 this.items = items; 22 } 23 24 static Pattern parse(string patternString) @safe pure 25 { 26 import std.string : split; 27 28 auto items = patternString.split('|'); 29 return Pattern(items); 30 } 31 32 @safe // TODO: when and how does it allocate tho? @nogc 33 auto matches(bool caseInsensitive)(string input) pure nothrow 34 { 35 return items.filter!((p) { 36 import std.algorithm : map, equal; 37 38 static if (caseInsensitive) 39 { 40 import std.ascii : toLower; 41 if (p.length != input.length) 42 return false; 43 foreach (index; 0 .. p.length) 44 { 45 if (toLower(p[index]) != toLower(input[index])) 46 return false; 47 } 48 return true; 49 } 50 else 51 return p == input; 52 }); 53 } 54 /// 55 unittest 56 { 57 import std.algorithm : equal; 58 auto p = Pattern.parse("a|A"); 59 { 60 enum caseInsensitive = true; 61 assert(equal(p.matches!(caseInsensitive)("a"), ["a", "A"])); 62 assert(equal(p.matches!(caseInsensitive)("b"), string[].init)); 63 } 64 { 65 enum caseInsensitive = false; 66 assert(equal(p.matches!(caseInsensitive)("a"), ["a"])); 67 assert(equal(p.matches!(caseInsensitive)("A"), ["A"])); 68 assert(equal(p.matches!(caseInsensitive)("b"), string[].init)); 69 } 70 } 71 // @safe @nogc 72 // string firstMatch(bool caseInsensitive)(string input) nothrow pure 73 // { 74 // static struct Result 75 // { 76 // bool matched; 77 // string pattern; 78 // } 79 // auto m = matches!caseInsensitive(input); 80 // if (m.empty) 81 // return Result(false, null); 82 // return Result(true, m.front); 83 // } 84 }