1 /** 2 * Boost Software License - Version 1.0 - August 17th, 2003 3 * 4 * Permission is hereby granted, free of charge, to any person or organization 5 * obtaining a copy of the software and accompanying documentation covered by 6 * this license (the "Software") to use, reproduce, display, distribute, 7 * execute, and transmit the Software, and to prepare derivative works of the 8 * Software, and to permit third-parties to whom the Software is furnished to 9 * do so, all subject to the following: 10 * 11 * The copyright notices in the Software and this entire statement, including 12 * the above license grant, this restriction and the following disclaimer, 13 * must be included in all copies of the Software, in whole or in part, and 14 * all derivative works of the Software, unless such copies or derivative 15 * works are solely in the form of machine-executable object code generated by 16 * a source language processor. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 21 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 22 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 */ 26 27 module dateparser.splitter; 28 29 debug(dateparser) import std.stdio; 30 import std.compiler; 31 import std.regex; 32 import std.traits; 33 import std.range; 34 35 // Compatibility patch for version 2.071 and earlier 36 // To be removed when support is dropped for 2.071 37 static if (version_major == 2 && version_minor < 72) 38 { 39 /** 40 * Split the given string on `pat`, but keep the matches in the final result. 41 * 42 * Params: 43 * r = the string to be split 44 * pat = the regex pattern 45 * Returns: 46 * A forward range of strings 47 */ 48 package auto splitterWithMatches(Range, RegEx)(Range r, RegEx pat) if ( 49 is(Unqual!(ElementEncodingType!Range) : dchar)) 50 { 51 return SplitterResult!(Range, RegEx)(r, pat); 52 } 53 54 // Issue 15831: This should be a Voldemort type, but due to linker slowdown 55 // it's a good idea to put this outside so we don't slowdown people's build 56 // times 57 package static struct SplitterResult(Range, alias RegEx = Regex) 58 { 59 private: 60 Range _input; 61 size_t _offset; 62 bool onMatch = false; 63 alias Rx = typeof(match(Range.init, RegEx.init)); 64 Rx _match; 65 66 @trusted this(Range input, RegEx separator) 67 { 68 _input = input; 69 if (_input.empty) 70 { 71 //there is nothing to match at all, make _offset > 0 72 _offset = 1; 73 } 74 else 75 { 76 _match = Rx(_input, separator); 77 } 78 } 79 80 public: 81 auto ref opSlice() 82 { 83 return this.save; 84 } 85 86 ///Forward range primitives. 87 @property Range front() 88 { 89 import std.algorithm : min; 90 91 assert(!empty && _offset <= _match.pre.length && _match.pre.length <= _input.length); 92 93 if (!onMatch) 94 return _input[_offset .. min($, _match.pre.length)]; 95 else 96 return _match.hit(); 97 } 98 99 ///ditto 100 @property bool empty() 101 { 102 return _offset >= _input.length; 103 } 104 105 ///ditto 106 void popFront() 107 { 108 assert(!empty); 109 if (_match.empty) 110 { 111 //No more separators, work is done here 112 _offset = _input.length + 1; 113 } 114 else 115 { 116 if (!onMatch) 117 { 118 //skip past the separator 119 _offset = _match.pre.length; 120 onMatch = true; 121 } 122 else 123 { 124 onMatch = false; 125 _offset += _match.hit.length; 126 _match.popFront(); 127 } 128 } 129 } 130 131 ///ditto 132 @property auto save() 133 { 134 return this; 135 } 136 } 137 } 138 else 139 { 140 import std.typecons; 141 142 package auto splitterWithMatches(Range, RegEx)(Range r, RegEx pat) 143 { 144 return splitter!(Yes.keepSeparators)(r, pat); 145 } 146 } 147 148 unittest 149 { 150 import std.algorithm.comparison : equal; 151 152 assert("2003.04.05" 153 .splitterWithMatches(regex(`([\.,])`, "g")) 154 .equal(["2003", ".", "04", ".", "05"])); 155 156 assert("10:00a.m." 157 .splitterWithMatches(regex(`([\.,])`, "g")) 158 .equal(["10:00a", ".", "m", "."])); 159 }