1 module nxt.ixes; 2 3 import std.algorithm : commonPrefix; 4 import std.meta : allSatisfy; 5 import std.range.primitives : isInputRange, isBidirectionalRange; 6 7 /** Get length of Common Prefix of $(D a) and $(D b). 8 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org 9 */ 10 auto commonPrefixLength(alias pred = "a == b", Rs...)(Rs rs) 11 if (rs.length >= 2 && 12 allSatisfy!(isInputRange, Rs)) 13 { 14 static if (rs.length == 2) 15 { 16 return commonPrefix!pred(rs[0], rs[1]).length; 17 } 18 else 19 { 20 static assert("TODO"); 21 import std.range : zip, StoppingPolicy; 22 import std.algorithm : countUntil, count; 23 const hit = zip(a, b).countUntil!(ab => ab[0] != ab[1]); // TODO if countUntil return zip(a, b).count upon failre... 24 return hit == -1 ? zip(a, b).count!pred : hit; // TODO ..then this would not have been needed 25 } 26 } 27 28 @safe pure unittest 29 { 30 assert(commonPrefixLength(`åäö_`, 31 `åäö-`) == 6); 32 } 33 34 @safe pure nothrow unittest 35 { 36 const x = [1, 2, 3, 10], y = [1, 2, 4, 10]; 37 void f() @safe pure nothrow @nogc 38 { 39 assert(commonPrefixLength(x, y) == 2); 40 } 41 f(); 42 assert(commonPrefixLength([1, 2, 3, 10], 43 [1, 2, 3]) == 3); 44 assert(commonPrefixLength([1, 2, 3, 0, 4], 45 [1, 2, 3, 9, 4]) == 3); 46 } 47 48 /** Get length of Suffix of $(D a) and $(D b). 49 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org 50 */ 51 auto commonSuffixLength(Rs...)(Rs rs) 52 if (rs.length == 2 && 53 allSatisfy!(isBidirectionalRange, Rs)) 54 { 55 import std.traits : isNarrowString; 56 import std.range: retro; 57 static if (isNarrowString!(typeof(rs[0])) && 58 isNarrowString!(typeof(rs[1]))) 59 { 60 import std..string: representation; 61 return commonPrefixLength(rs[0].representation.retro, 62 rs[1].representation.retro); 63 } 64 else 65 { 66 return commonPrefixLength(rs[0].retro, 67 rs[1].retro); 68 } 69 } 70 71 @safe pure unittest 72 { 73 const x = [1, 2, 3, 10, 11, 12]; 74 const y = [1, 2, 4, 10, 11, 12]; 75 void f() @safe pure nothrow @nogc 76 { 77 assert(commonPrefixLength(x, y) == 2); 78 } 79 f(); 80 assert(commonSuffixLength(x, y) == 3); 81 assert(commonSuffixLength([10, 1, 2, 3], 82 [1, 2, 3]) == 3); 83 } 84 85 @safe pure unittest 86 { 87 assert(commonSuffixLength(`_åäö`, 88 `-åäö`) == 6); 89 } 90 91 /** Get Count of Prefix of $(D a) and $(D b). 92 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org 93 */ 94 auto commonPrefixCount(alias pred = "a == b", Rs...)(Rs rs) 95 if (rs.length == 2 && 96 allSatisfy!(isInputRange, Rs)) 97 { 98 import std.algorithm.searching : count; 99 import std.traits : isNarrowString; 100 static if (isNarrowString!(typeof(rs[0])) && 101 isNarrowString!(typeof(rs[1]))) 102 { 103 import std.utf: byDchar; 104 return commonPrefix!pred(rs[0].byDchar, 105 rs[1].byDchar).count; 106 } 107 else 108 { 109 return commonPrefix!pred(rs[0], rs[1]).count; 110 } 111 } 112 113 @safe pure unittest 114 { 115 assert(commonPrefixCount([1, 2, 3, 10], 116 [1, 2, 3]) == 3); 117 assert(commonPrefixCount(`åäö_`, 118 `åäö-`) == 3); 119 } 120 121 /** Get Common Suffix of $(D a) and $(D b). 122 TODO Copy implementation of commonPrefix into commonSuffix to splitter 123 */ 124 auto commonSuffix(Rs...)(Rs rs) 125 if (rs.length == 2 && 126 allSatisfy!(isBidirectionalRange, Rs)) 127 { 128 import std.range : retro; 129 import std.conv : to; 130 import std.array : array; 131 return commonPrefix(rs[0].retro, 132 rs[1].retro).array.retro; 133 } 134 135 @safe pure unittest 136 { 137 import std.algorithm.comparison : equal; 138 assert(equal(commonSuffix(`_åäö`, 139 `-åäö`), `åäö`)); 140 } 141 142 // @safe pure unittest 143 // { 144 // import std.algorithm.comparison : equal; 145 // import nxt.splitter_ex : splitterASCIIAmong; 146 // import std.range : retro; 147 // import std.range.primitives : ElementType; 148 // import std.array : array; 149 // assert(equal(commonSuffix(`_å-ä-ö`, 150 // `-å-ä-ö`).retro.splitterASCIIAmong!('-').array, // TODO how should this be solved? 151 // [`ö`, `ä`, `å`])); 152 // } 153 154 /** Get Count of Common Suffix of $(D a) and $(D b). 155 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org 156 */ 157 auto commonSuffixCount(alias pred = "a == b", Rs...)(Rs rs) 158 if (rs.length == 2 && 159 allSatisfy!(isBidirectionalRange, Rs)) 160 { 161 import std.range : retro; 162 return commonPrefixCount!pred(rs[0].retro, 163 rs[1].retro); 164 } 165 166 @safe pure unittest 167 { 168 assert(commonSuffixCount(`_`, `-`) == 0); 169 assert(commonSuffixCount(`_å`, `-å`) == 1); 170 assert(commonSuffixCount(`_åä`, `-åä`) == 2); 171 assert(commonSuffixCount(`_åäö`, `-åäö`) == 3); 172 173 import std.algorithm.comparison : among; 174 assert(commonSuffixCount!((a, b) => (a == b && a == 'ö'))(`_åäö`, `-åäö`) == 1); 175 assert(commonSuffixCount!((a, b) => (a == b && a.among!('ä', 'ö')))(`_åäö`, `-åäö`) == 2); 176 } 177 178 /** Get length of Common Prefix of rs $(D rs). 179 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org 180 */ 181 // auto commonPrefixLengthN(R...)(R rs) if (rs.length == 2) 182 // { 183 // import std.range: zip; 184 // return zip!((a, b) => a != b)(rs); 185 // } 186 187 // unittest 188 // { 189 // assert(commonPrefixLengthN([1, 2, 3, 10], 190 // [1, 2, 4, 10]) == 2); 191 // }