diff --git a/std/string.d b/std/string.d index 5b9cb7a24..1dae55aaa 100644 --- a/std/string.d +++ b/std/string.d @@ -2142,9 +2142,9 @@ string[dchar] transTable3 = ['e' : "5", 'o' : "orange"]; assert(translate("hello world", transTable3) == "h5llorange worangerld"); -------------------- +/ -C1[] translate(C1, C2 = char)(C1[] str, - dchar[dchar] transTable, - const(C2)[] toRemove = null) @safe +C1[] translate(C1, C2 = immutable char)(C1[] str, + dchar[dchar] transTable, + const(C2)[] toRemove = null) @safe if(isSomeChar!C1 && isSomeChar!C2) { return translateImpl(str, transTable, toRemove); @@ -2200,22 +2200,17 @@ unittest to!T("\U00010143 ")) == to!S("hell0w0rld")); } + + auto s = to!S("hello world"); + dchar[dchar] transTable = ['h' : 'q', 'l' : '5']; + static assert(is(typeof(s) == typeof(translate(s, transTable)))); } - - string a = "hello world"; - const(char)[] b = "hello world"; - char[] c = "hello world".dup; - dchar[dchar] transTable = ['h' : 'q', 'l' : '5']; - - static assert(is(typeof(a) == typeof(translate(a, transTable)))); - static assert(is(typeof(b) == typeof(translate(b, transTable)))); - static assert(is(typeof(c) == typeof(translate(c, transTable)))); } /++ Ditto +/ -C1[] translate(C1, S, C2 = char)(C1[] str, - S[dchar] transTable, - const(C2)[] toRemove = null) @safe +C1[] translate(C1, S, C2 = immutable char)(C1[] str, + S[dchar] transTable, + const(C2)[] toRemove = null) @safe if(isSomeChar!C1 && isSomeString!S && isSomeChar!C2) { return translateImpl(str, transTable, toRemove); @@ -2256,16 +2251,11 @@ unittest to!T("\U00010143 ")) == to!S("hellowlwowlrld")); } + + auto s = to!S("hello world"); + string[dchar] transTable = ['h' : "silly", 'l' : "putty"]; + static assert(is(typeof(s) == typeof(translate(s, transTable)))); } - - string a = "hello world"; - const(char)[] b = "hello world"; - char[] c = "hello world".dup; - string[dchar] transTable = ['h' : "silly", 'l' : "putty"]; - - static assert(is(typeof(a) == typeof(translate(a, transTable)))); - static assert(is(typeof(b) == typeof(translate(b, transTable)))); - static assert(is(typeof(c) == typeof(translate(c, transTable)))); } private auto translateImpl(C1, T, C2)(C1[] str, @@ -2900,41 +2890,51 @@ unittest } -/*********************************************** - * Replaces characters in str[] that are in from[] - * with corresponding characters in to[] and returns the resulting - * string. - * Params: - * modifiers = a string of modifier characters - * Modifiers: +/++ + Replaces the characters in $(D str) which are in $(D from) with the + the corresponding characters in $(D to) and returns the resulting string. + + $(D tr) is based on + $(WEB pubs.opengroup.org/onlinepubs/9699919799/utilities/_tr.html, Posix's tr), + though it doesn't do everything that the Posix utility does. + + Params: + str = The original string. + from = The characters to replace. + to = The characters to replace with. + modifiers = String containing modifiers. + + Modifiers:
Modifier Description -
c Complement the list of characters in from[] -
d Removes matching characters with no corresponding replacement in to[] -
s Removes adjacent duplicates in the replaced characters +
c Complement the list of characters in $(D from). +
d Removes matching characters with no corresponding + replacement in $(D to). +
s Removes adjacent duplicates in the replaced + characters.
- If modifier d is present, then the number of characters - in to[] may be only 0 or 1. + If the modifier $(D 'd') is present, then the number of characters in + $(D to) may be only $(D 0) or $(D 1). - If modifier d is not present and to[] is null, - then to[] is taken _to be the same as from[]. + If the modifier $(D 'd') is $(I not) present, and $(D to) is empty, then + $(D to) is taken to be the same as $(D from). - If modifier d is not present and to[] is shorter - than from[], then to[] is extended by replicating the - last character in to[]. + If the modifier $(D 'd') is $(I not) present, and $(D to) is shorter than + $(D from), then $(D to) is extended by replicating the last charcter in + $(D to). - Both from[] and to[] may contain ranges using the - - character, for example a-d is synonymous with abcd. - Neither accept a leading ^ as meaning the complement of - the string (use the c modifier for that). - */ - -string tr(const(char)[] str, const(char)[] from, const(char)[] to, const(char)[] modifiers = null) + Both $(D from) and $(D to) may contain ranges using the $(D '-') character + (e.g. $(D "a-d") is synonymous with $(D "abcd).) Neither accept a leading + $(D '^') as meaning the complement of the string (use the $(D 'c') modifier + for that). + +/ +C1[] tr(C1, C2, C3, C4 = immutable char) + (C1[] str, const(C2)[] from, const(C3)[] to, const(C4)[] modifiers = null) { - int mod_c; - int mod_d; - int mod_s; + bool mod_c; + bool mod_d; + bool mod_s; foreach (char c; modifiers) { @@ -2947,12 +2947,11 @@ string tr(const(char)[] str, const(char)[] from, const(char)[] to, const(char)[] } } - if (to is null && !mod_d) - to = from; + if (to.empty && !mod_d) + to = std.conv.to!(typeof(to))(from); - char[] result = new char[str.length]; - result.length = 0; - int m; + auto result = appender!(C1[])(); + bool modified; dchar lastc; foreach (dchar c; str) @@ -2965,11 +2964,9 @@ string tr(const(char)[] str, const(char)[] from, const(char)[] to, const(char)[] for (size_t i = 0; i < from.length; ) { dchar f = std.utf.decode(from, i); - //writefln("\tf = '%s', c = '%s', lastf = '%x', '%x', i = %d, %d", f, c, lastf, dchar.init, i, from.length); if (f == '-' && lastf != dchar.init && i < from.length) { dchar nextf = std.utf.decode(from, i); - //writefln("\tlastf = '%s', c = '%s', nextf = '%s'", lastf, c, nextf); if (lastf <= c && c <= nextf) { n += c - lastf - 1; @@ -2997,14 +2994,12 @@ string tr(const(char)[] str, const(char)[] from, const(char)[] to, const(char)[] Lfound: // Find the nth character in to[] - //writefln("\tc = '%s', n = %d", c, n); dchar nextt; for (size_t i = 0; i < to.length; ) { dchar t = std.utf.decode(to, i); if (t == '-' && lastt != dchar.init && i < to.length) { nextt = std.utf.decode(to, i); - //writefln("\tlastt = '%s', c = '%s', nextt = '%s', n = %d", lastt, c, nextt, n); n -= nextt - lastt; if (n < 0) { @@ -3027,60 +3022,57 @@ string tr(const(char)[] str, const(char)[] from, const(char)[] to, const(char)[] newc = nextt; Lnewc: - if (mod_s && m && newc == lastc) + if (mod_s && modified && newc == lastc) continue; - std.utf.encode(result, newc); - m = 1; + result.put(newc); + assert(newc != dchar.init); + modified = true; lastc = newc; continue; Lnotfound: - std.utf.encode(result, c); + result.put(c); lastc = c; - m = 0; + modified = false; } - return assumeUnique(result); + + return result.data; } unittest { debug(string) printf("std.string.tr.unittest\n"); + import std.algorithm; - string r; - //writefln("r = '%s'", r); + foreach(S; TypeTuple!(char[], const(char)[], immutable(char)[], + wchar[], const(wchar)[], immutable(wchar)[], + dchar[], const(dchar)[], immutable(dchar)[])) + { + foreach(T; TypeTuple!(char[], const(char)[], immutable(char)[], + wchar[], const(wchar)[], immutable(wchar)[], + dchar[], const(dchar)[], immutable(dchar)[])) + { + foreach(U; TypeTuple!(char[], const(char)[], immutable(char)[], + wchar[], const(wchar)[], immutable(wchar)[], + dchar[], const(dchar)[], immutable(dchar)[])) + { + assert(equal(tr(to!S("abcdef"), to!T("cd"), to!U("CD")), "abCDef")); + assert(equal(tr(to!S("abcdef"), to!T("b-d"), to!U("B-D")), "aBCDef")); + assert(equal(tr(to!S("abcdefgh"), to!T("b-dh"), to!U("B-Dx")), "aBCDefgx")); + assert(equal(tr(to!S("abcdefgh"), to!T("b-dh"), to!U("B-CDx")), "aBCDefgx")); + assert(equal(tr(to!S("abcdefgh"), to!T("b-dh"), to!U("B-BCDx")), "aBCDefgx")); + assert(equal(tr(to!S("abcdef"), to!T("ef"), to!U("*"), to!S("c")), "****ef")); + assert(equal(tr(to!S("abcdef"), to!T("ef"), to!U(""), to!T("d")), "abcd")); + assert(equal(tr(to!S("hello goodbye"), to!T("lo"), to!U(""), to!U("s")), "helo godbye")); + assert(equal(tr(to!S("hello goodbye"), to!T("lo"), to!U("x"), "s"), "hex gxdbye")); + assert(equal(tr(to!S("14-Jul-87"), to!T("a-zA-Z"), to!U(" "), "cs"), " Jul ")); + assert(equal(tr(to!S("Abc"), to!T("AAA"), to!U("XYZ")), "Xbc")); + } + } - r = tr("abcdef", "cd", "CD"); - assert(r == "abCDef"); - - r = tr("abcdef", "b-d", "B-D"); - assert(r == "aBCDef"); - - r = tr("abcdefgh", "b-dh", "B-Dx"); - assert(r == "aBCDefgx"); - - r = tr("abcdefgh", "b-dh", "B-CDx"); - assert(r == "aBCDefgx"); - - r = tr("abcdefgh", "b-dh", "B-BCDx"); - assert(r == "aBCDefgx"); - - r = tr("abcdef", "ef", "*", "c"); - assert(r == "****ef"); - - r = tr("abcdef", "ef", "", "d"); - assert(r == "abcd"); - - r = tr("hello goodbye", "lo", null, "s"); - assert(r == "helo godbye"); - - r = tr("hello goodbye", "lo", "x", "s"); - assert(r == "hex gxdbye"); - - r = tr("14-Jul-87", "a-zA-Z", " ", "cs"); - assert(r == " Jul "); - - r = tr("Abc", "AAA", "XYZ"); - assert(r == "Xbc"); + auto s = to!S("hello world"); + static assert(is(typeof(s) == typeof(tr(s, "he", "if")))); + } }