1 /* 2 * Hunt - A refined core library for D programming language. 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.text.Pattern; 13 14 import hunt.text.Common; 15 import hunt.text.StringUtils; 16 17 import std.string; 18 19 20 abstract class Pattern { 21 22 private __gshared AllMatch ALL_MATCH; 23 24 shared static this() { 25 ALL_MATCH = new AllMatch(); 26 } 27 28 /** 29 * Matches a string according to the specified pattern 30 * @param str Target string 31 * @return If it returns null, that represents matching failure, 32 * else it returns an array contains all strings are matched. 33 */ 34 abstract string[] match(string str); 35 36 static Pattern compile(string pattern, string wildcard) { 37 bool startWith = pattern.startsWith(wildcard); 38 bool endWith = pattern.endsWith(wildcard); 39 string[] array = StringUtils.split(pattern, wildcard); 40 41 switch (array.length) { 42 case 0: 43 return ALL_MATCH; 44 case 1: 45 if (startWith && endWith) 46 return new HeadAndTailMatch(array[0]); 47 48 if (startWith) 49 return new HeadMatch(array[0]); 50 51 if (endWith) 52 return new TailMatch(array[0]); 53 54 return new EqualsMatch(pattern); 55 default: 56 return new MultipartMatch(startWith, endWith, array); 57 } 58 } 59 60 61 private static class MultipartMatch : Pattern { 62 63 private bool startWith, endWith; 64 private string[] parts; 65 private int num; 66 67 this(bool startWith, bool endWith, string[] parts) { 68 // super(); 69 this.startWith = startWith; 70 this.endWith = endWith; 71 this.parts = parts; 72 num = cast(int)parts.length - 1; 73 if(startWith) 74 num++; 75 if(endWith) 76 num++; 77 } 78 79 override 80 string[] match(string str) { 81 int currentIndex = -1; 82 int lastIndex = -1; 83 string[] ret = new string[num]; 84 85 for (int i = 0; i < parts.length; i++) { 86 string part = parts[i]; 87 int j = startWith ? i : i - 1; 88 currentIndex = cast(int)str.indexOf(part, lastIndex + 1); 89 90 if (currentIndex > lastIndex) { 91 if(i != 0 || startWith) 92 ret[j] = str.substring(lastIndex + 1, currentIndex); 93 94 lastIndex = currentIndex + cast(int)part.length - 1; 95 continue; 96 } 97 return null; 98 } 99 100 if(endWith) 101 ret[num - 1] = str.substring(lastIndex + 1); 102 103 return ret; 104 } 105 106 } 107 108 private static class TailMatch : Pattern { 109 private string part; 110 111 this(string part) { 112 this.part = part; 113 } 114 115 override 116 string[] match(string str) { 117 int currentIndex = cast(int)str.indexOf(part); 118 if(currentIndex == 0) { 119 return [str.substring(cast(int)part.length)]; 120 } 121 return null; 122 } 123 } 124 125 private static class HeadMatch : Pattern { 126 private string part; 127 128 this(string part) { 129 this.part = part; 130 } 131 132 override 133 string[] match(string str) { 134 int currentIndex = cast(int)str.indexOf(part); 135 if(currentIndex + part.length == str.length) { 136 return [str.substring(0, currentIndex)]; 137 } 138 return null; 139 } 140 141 142 } 143 144 private static class HeadAndTailMatch : Pattern { 145 private string part; 146 147 this(string part) { 148 this.part = part; 149 } 150 151 override 152 string[] match(string str) { 153 int currentIndex = cast(int)str.indexOf(part); 154 if(currentIndex >= 0) { 155 string[] ret = [str[0 .. currentIndex], 156 str.substring(currentIndex + cast(int)part.length, cast(int)str.length) ]; 157 return ret; 158 } 159 return null; 160 } 161 162 163 } 164 165 private static class EqualsMatch : Pattern { 166 private string pattern; 167 168 this(string pattern) { 169 this.pattern = pattern; 170 } 171 172 override 173 string[] match(string str) { 174 return pattern.equals(str) ? new string[0] : null; 175 } 176 } 177 178 private static class AllMatch : Pattern { 179 180 override 181 string[] match(string str) { 182 return [str]; 183 } 184 } 185 }