Changeset 1733
- Timestamp:
- 07/06/10 05:34:59 (14 years ago)
- Files:
-
- trunk/phobos/std/array.d (modified) (3 diffs)
- trunk/phobos/std/complex.d (modified) (1 diff)
- trunk/phobos/std/conv.d (modified) (3 diffs)
- trunk/phobos/std/file.d (modified) (3 diffs)
- trunk/phobos/std/format.d (modified) (6 diffs)
- trunk/phobos/std/json.d (modified) (3 diffs)
- trunk/phobos/std/process.d (modified) (1 diff)
- trunk/phobos/std/regex.d (modified) (3 diffs)
- trunk/phobos/std/string.d (modified) (2 diffs)
- trunk/phobos/std/xml.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/phobos/std/array.d
r1725 r1733 55 55 else 56 56 { 57 57 e = r.front; 58 58 } 59 59 r.popFront; 60 60 } 61 61 return result; 62 62 } 63 63 else 64 64 { 65 auto a = Appender!(E[])();65 auto a = appender!(E[])(); 66 66 foreach (e; r) 67 67 { 68 68 a.put(e); 69 69 } 70 70 return a.data; 71 71 } 72 72 // // 2. Initialize the memory 73 73 // size_t constructedElements = 0; 74 74 // scope(failure) 75 75 // { … … 694 694 allocateCapacity(); 695 695 } 696 696 697 697 /** 698 698 Returns the capacity of the array (the maximum number of 699 699 elements the managed array can accommodate before triggering a 700 700 reallocation). 701 701 */ 702 702 @property ref size_t capacity() 703 703 { 704 enforce(pArray); 704 enforce(pArray, "You must initialize Appender by calling the" 705 " appender function before using it"); 705 706 auto p = cast(ubyte*) (pArray.ptr + pArray.length); 706 707 while (cast(size_t) p & 3) ++p; 707 708 return *cast(size_t *) p; 708 709 } 709 710 710 711 /** 711 712 Returns the managed array. 712 713 */ 713 T[] data()714 @property T[] data() 714 715 { 715 716 return cast(typeof(return)) (pArray ? *pArray : null); 716 717 } 717 718 718 719 /** 719 720 Appends one item to the managed array. 720 721 */ 721 722 void put(U)(U item) if (isImplicitlyConvertible!(U, T) || 722 723 isSomeChar!T && isSomeChar!U) 723 724 { 725 enforce(pArray, "You must initialize Appender by calling the" 726 " appender function before using it"); 724 727 static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof) 725 728 { 726 729 // must do some transcoding around here 727 730 Unqual!T[T.sizeof == 1 ? 4 : 2] encoded; 728 731 auto len = std.utf.encode(encoded, item); 729 732 put(encoded[0 .. len]); 730 733 } 731 734 else 732 735 { 733 736 if (!pArray) … … 751 754 } 752 755 } 753 756 } 754 757 755 758 /** 756 759 Appends an entire range to the managed array. 757 760 */ 758 761 void put(Range)(Range items) if (isForwardRange!Range 759 762 && is(typeof(Appender.init.put(items.front)))) 760 763 { 764 enforce(pArray, "You must initialize Appender by calling the" 765 " appender function before using it"); 761 766 static if (is(typeof(*pArray ~= items))) 762 767 { 763 768 if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; 764 769 *pArray ~= items; 765 770 allocateCapacity(); 766 771 } 767 772 else 768 773 { 769 774 //pragma(msg, Range.stringof); 770 775 // Generic input range trunk/phobos/std/complex.d
r1532 r1733 502 502 auto c = Complex!float(2.0, 2.0); 503 503 z = c; 504 504 assert (z == c); 505 505 assert (z.re == 2.0 && z.im == 2.0); 506 506 } 507 507 508 508 unittest 509 509 { 510 510 // Convert to string. 511 511 auto z1 = Complex!real(0.123456789, 0.123456789); 512 Appender!string s1;512 auto s1 = appender!string(); 513 513 z1.toString(s1, "s"); 514 514 assert (s1.data == "0.123457+0.123457i"); 515 515 516 516 auto z2 = z1.conj; 517 Appender!string s2;517 auto s2 = appender!string(); 518 518 z2.toString(s2, ".8e"); 519 519 assert (s2.data == "1.23456789e-01-1.23456789e-01i"); 520 520 } 521 521 522 522 523 523 524 524 525 525 /* Fold Complex!(Complex!T) to Complex!T. 526 526 527 527 The rationale for this is that just like the real line is a trunk/phobos/std/conv.d
r1717 r1733 167 167 // array-to-string conversion 168 168 static if (is(S == void[]) 169 169 || is(S == const(void)[]) || is(S == immutable(void)[])) { 170 170 auto raw = cast(const(ubyte)[]) s; 171 171 enforce(raw.length % Char.sizeof == 0, "Alignment mismatch" 172 172 " in converting a " ~ S.stringof ~ " to a " ~ T.stringof); 173 173 auto result = new Char[raw.length / Char.sizeof]; 174 174 memcpy(result.ptr, s.ptr, s.length); 175 175 return cast(T) result; 176 176 } else { 177 Appender!(Char[]) result;177 auto result = appender!(Char[])(); 178 178 result.put(leftBracket); 179 179 foreach (i, e; s) { 180 180 if (i) result.put(separator); 181 181 result.put(to!T(e)); 182 182 } 183 183 result.put(rightBracket); 184 184 return cast(T) result.data; 185 185 } 186 186 } 187 187 … … 199 199 /** 200 200 Associative array to string conversion. The left bracket, key-value 201 201 separator, element separator, and right bracket are configurable. 202 202 Each element is printed by calling $(D to!T). 203 203 */ 204 204 T to(T, S)(S s, in T leftBracket = "[", in T keyval = ":", 205 205 in T separator = ", ", in T rightBracket = "]") 206 206 if (isAssociativeArray!(S) && isSomeString!(T)) 207 207 { 208 208 alias Unqual!(typeof(T.init[0])) Char; 209 Appender!(Char[]) result;209 auto result = appender!(Char[])(); 210 210 // hash-to-string conversion 211 211 result.put(leftBracket); 212 212 bool first = true; 213 213 foreach (k, v; s) { 214 214 if (!first) result.put(separator); 215 215 else first = false; 216 216 result.put(to!(T)(k)); 217 217 result.put(keyval); 218 218 result.put(to!(T)(v)); 219 219 } … … 264 264 T to(T, S)(S s, in T left = S.stringof~"(", in T separator = ", ", 265 265 in T right = ")") 266 266 if (is(S == struct) && isSomeString!(T) && !is(typeof(&S.init.toString))) 267 267 { 268 268 Tuple!(FieldTypeTuple!(S)) * t = void; 269 269 static if ((*t).sizeof == S.sizeof) 270 270 { 271 271 // ok, attempt to forge the tuple 272 272 t = cast(typeof(t)) &s; 273 273 alias Unqual!(typeof(T.init[0])) Char; 274 Appender!(Char[]) app;274 auto app = appender!(Char[])(); 275 275 app.put(left); 276 276 foreach (i, e; t.field) 277 277 { 278 278 if (i > 0) app.put(to!(T)(separator)); 279 279 app.put(to!(T)(e)); 280 280 } 281 281 app.put(right); 282 282 return cast(T) app.data; 283 283 } 284 284 else trunk/phobos/std/file.d
r1725 r1733 1449 1449 * auto dirs = std.file.listdir(args[1]); 1450 1450 * 1451 1451 * foreach (d; dirs) 1452 1452 * writefln(d); 1453 1453 * } 1454 1454 * ---- 1455 1455 */ 1456 1456 1457 1457 string[] listdir(in char[] pathname) 1458 1458 { 1459 Appender!(string[]) result;1459 auto result = appender!(string[])(); 1460 1460 1461 1461 bool listing(string filename) 1462 1462 { 1463 1463 result.put(filename); 1464 1464 return true; // continue 1465 1465 } 1466 1466 1467 1467 listdir(pathname, &listing); 1468 1468 return result.data; 1469 1469 } … … 1509 1509 * auto d_source_files = std.file.listdir(args[1], RegExp(r"\.(d|obj)$")); 1510 1510 * 1511 1511 * foreach (d; d_source_files) 1512 1512 * writefln(d); 1513 1513 * } 1514 1514 * ---- 1515 1515 */ 1516 1516 1517 1517 string[] listdir(in char[] pathname, in char[] pattern) 1518 1518 { 1519 Appender!(string[]) result;1519 auto result = appender!(string[])(); 1520 1520 1521 1521 bool callback(DirEntry* de) 1522 1522 { 1523 1523 if (de.isdir) 1524 1524 listdir(de.name, &callback); 1525 1525 else 1526 1526 { 1527 1527 if (std.path.fnmatch(de.name, pattern)) 1528 1528 result.put(de.name); 1529 1529 } … … 1531 1531 } 1532 1532 1533 1533 listdir(pathname, &callback); 1534 1534 return result.data; 1535 1535 } 1536 1536 1537 1537 /** Ditto */ 1538 1538 1539 1539 string[] listdir(in char[] pathname, RegExp r) 1540 1540 { 1541 Appender!(string[]) result;1541 auto result = appender!(string[])(); 1542 1542 1543 1543 bool callback(DirEntry* de) 1544 1544 { 1545 1545 if (de.isdir) 1546 1546 listdir(de.name, &callback); 1547 1547 else 1548 1548 { 1549 1549 if (r.test(de.name)) 1550 1550 result.put(de.name); 1551 1551 } trunk/phobos/std/format.d
r1732 r1733 1699 1699 } // end switch 1700 1700 } // end for 1701 1701 enforce(false, text("Incorrect format specifier: ", fmt)); 1702 1702 } 1703 1703 } 1704 1704 1705 1705 //------------------------------------------------------------------------------ 1706 1706 // Writes characters in the format strings up to the first format 1707 1707 // specifier and updates the format specifier to remove the written 1708 1708 // portion The updated format fmt does not include the '%' 1709 private void writeUpToFormatSpec(OutRange, S)( refOutRange w, ref S fmt)1709 private void writeUpToFormatSpec(OutRange, S)(OutRange w, ref S fmt) 1710 1710 { 1711 1711 for (size_t i = 0; i < fmt.length; ++i) 1712 1712 { 1713 1713 if (fmt[i] != '%') continue; 1714 1714 if (fmt[++i] != '%') 1715 1715 { 1716 1716 // spec found, print and bailout 1717 1717 w.put(fmt[0 .. i - 1]); 1718 1718 fmt = fmt[i .. $]; 1719 1719 return; … … 1745 1745 writeUpToFormatSpec(w, fmt); 1746 1746 assert(w.data == "ab%cd%ef" && fmt == "sg%%h%sij"); 1747 1747 writeUpToFormatSpec(w, fmt); 1748 1748 assert(w.data == "ab%cd%efsg%h" && fmt == "sij"); 1749 1749 } 1750 1750 1751 1751 /* 1752 1752 * Formats an integral number 'arg' according to 'f' and writes it to 1753 1753 * 'w'. 1754 1754 */ 1755 private void formatImpl(Writer, D)( refWriter w, D argx, FormatInfo f)1755 private void formatImpl(Writer, D)(Writer w, D argx, FormatInfo f) 1756 1756 if (isIntegral!(D)) 1757 1757 { 1758 1758 Unqual!(D) arg = argx; 1759 1759 if (f.spec == 'r') 1760 1760 { 1761 1761 // raw write, skip all else and write the thing 1762 1762 auto begin = cast(const char*) &arg; 1763 1763 if (std.system.endian == Endian.LittleEndian && f.flPlus 1764 1764 || std.system.endian == Endian.BigEndian && f.flDash) 1765 1765 { … … 1877 1877 w.put(digits); 1878 1878 } 1879 1879 // write the spaces to the right if left-align 1880 1880 if (!leftPad) foreach (i ; 0 .. spacesToPrint) w.put(' '); 1881 1881 } 1882 1882 1883 1883 /* 1884 1884 * Formats a floating point number 'arg' according to 'f' and writes 1885 1885 * it to 'w'. 1886 1886 */ 1887 private void formatImpl(Writer, D)( refWriter w, D obj, FormatInfo f)1887 private void formatImpl(Writer, D)(Writer w, D obj, FormatInfo f) 1888 1888 if (isFloatingPoint!(D)) 1889 1889 { 1890 1890 if (f.spec == 'r') 1891 1891 { 1892 1892 // raw write, skip all else and write the thing 1893 1893 auto begin = cast(const char*) &obj; 1894 1894 if (std.system.endian == Endian.LittleEndian && f.flPlus 1895 1895 || std.system.endian == Endian.BigEndian && f.flDash) 1896 1896 { 1897 1897 // must swap bytes … … 1931 1931 f.width, 1932 1932 // negative precision is same as no precision specified 1933 1933 f.precision == FormatInfo.UNSPECIFIED ? -1 : f.precision, 1934 1934 obj); 1935 1935 if (n < 0) throw new FormatError("floating point formatting failure"); 1936 1936 w.put(buf[0 .. strlen(buf.ptr)]); 1937 1937 } 1938 1938 1939 1939 unittest 1940 1940 { 1941 Appender!(string) a;1941 auto a = appender!(string)(); 1942 1942 immutable real x = 5.5; 1943 1943 FormatInfo f; 1944 1944 formatImpl(a, x, f); 1945 1945 assert(a.data == "5.5"); 1946 1946 } 1947 1947 1948 1948 /* 1949 1949 * Formats an object of type 'D' according to 'f' and writes it to 1950 1950 * 'w'. The pointer 'arg' is assumed to point to an object of type 1951 1951 * 'D'. 1952 1952 */ 1953 private void formatGeneric(Writer, D)( refWriter w, const(void)* arg,1953 private void formatGeneric(Writer, D)(Writer w, const(void)* arg, 1954 1954 FormatInfo f) 1955 1955 { 1956 1956 auto obj = *cast(D*) arg; 1957 1957 static if (is(const(D) == const(void[]))) { 1958 1958 auto s = cast(const char[]) obj; 1959 1959 w.put(s); 1960 1960 } else static if (is(D Original == enum)) { 1961 1961 formatGeneric!(Writer, Original)(w, arg, f); 1962 1962 } else static if (is(D Original == typedef)) { 1963 1963 formatGeneric!(Writer, Original)(w, arg, f); … … 2137 2137 string $(D fmt) and writes the result to $(D w). $(D F) must be $(D 2138 2138 char), $(D wchar), or $(D dchar). 2139 2139 2140 2140 Example: 2141 2141 ------------------------- 2142 2142 import std.c.stdio; 2143 2143 import std.format; 2144 2144 2145 2145 string myFormat(A...)(A args) 2146 2146 { 2147 Appender!(string) writer;2147 auto writer = appender!string(); 2148 2148 std.format.formattedWrite(writer, 2149 2149 "%s et %s numeris romanis non sunt", args); 2150 2150 return writer.data; 2151 2151 } 2152 2152 ... 2153 2153 int x = 42; 2154 2154 assert(myFormat(x, 0) == "42 et 0 numeris romanis non sunt"); 2155 2155 ------------------------ 2156 2156 2157 2157 $(D formattedWrite) supports positional parameter syntax in $(WEB 2158 2158 opengroup.org/onlinepubs/009695399/functions/printf.html, POSIX) 2159 2159 style. Example: 2160 2160 2161 2161 ------------------------- 2162 Appender!(string) writer;2162 auto writer = appender!string(); 2163 2163 std.format.formattedWrite(writer, "Date: %2$s %1$s", "October", 5); 2164 2164 assert(writer.data == "Date: 5 October"); 2165 2165 ------------------------ 2166 2166 2167 2167 The positional and non-positional styles can be mixed in the same 2168 2168 format string. (POSIX leaves this behavior undefined.) The internal 2169 2169 counter for non-positional parameters tracks the next parameter after 2170 2170 the largest positional parameter already used. 2171 2171 2172 2172 Warning: 2173 2173 This is the function internally used by writef* but it's still 2174 2174 undergoing active development. Do not rely on it. 2175 2175 */ 2176 2176 2177 void formattedWrite(Writer, F, A...)( refWriter w, const(F)[] fmt, A args)2177 void formattedWrite(Writer, F, A...)(Writer w, const(F)[] fmt, A args) 2178 2178 { 2179 2179 enum len = args.length; 2180 void function( refWriter, const(void)*, FormatInfo) funs[len] = void;2180 void function(Writer, const(void)*, FormatInfo) funs[len] = void; 2181 2181 const(void)* argsAddresses[len] = void; 2182 2182 foreach (i, arg; args) 2183 2183 { 2184 2184 funs[i] = &formatGeneric!(Writer, typeof(arg)); 2185 2185 argsAddresses[i] = &arg; 2186 2186 } 2187 2187 // Are we already done with formats? Then just dump each parameter in turn 2188 2188 uint currentArg = 0; 2189 2189 for (;;) 2190 2190 { … … 2259 2259 funs[currentArg](w, argsAddresses[currentArg], spec); 2260 2260 ++currentArg; 2261 2261 } 2262 2262 } 2263 2263 } 2264 2264 2265 2265 /* ======================== Unit Tests ====================================== */ 2266 2266 2267 2267 unittest 2268 2268 { 2269 auto stream = appender ((string*).init);2269 auto stream = appender!string(); 2270 2270 formattedWrite(stream, "%s", 1.1); 2271 2271 assert(stream.data == "1.1", stream.data); 2272 2272 } 2273 2273 2274 2274 unittest 2275 2275 { 2276 auto stream = appender ((string*).init);2276 auto stream = appender!string(); 2277 2277 formattedWrite(stream, "%u", 42); 2278 2278 assert(stream.data == "42", stream.data); 2279 2279 } 2280 2280 2281 2281 unittest 2282 2282 { 2283 2283 // testing raw writes 2284 2284 string s; 2285 2285 auto w = appender(&s); 2286 2286 uint a = 0x02030405; trunk/phobos/std/json.d
r1480 r1733 123 123 auto c2 = peekChar(); 124 124 static if (!CaseSensitive) c2 = tolower(c2); 125 125 126 126 if(c2 != c) return false; 127 127 128 128 getChar(); 129 129 return true; 130 130 } 131 131 132 132 string parseString() { 133 Appender!string str;133 auto str = appender!string(); 134 134 135 135 Next: 136 136 switch(peekChar()) { 137 137 case '"': 138 138 getChar(); 139 139 break; 140 140 141 141 case '\\': 142 142 getChar(); 143 143 auto c = getChar(); … … 216 216 checkChar(']'); 217 217 break; 218 218 219 219 case '"': 220 220 value.type = JSON_TYPE.STRING; 221 221 value.str = parseString(); 222 222 break; 223 223 224 224 case '0': .. case '9': 225 225 case '-': 226 Appender!string number;226 auto number = appender!string(); 227 227 bool isFloat; 228 228 229 229 void readInteger() { 230 230 if(!isdigit(c)) error("Digit expected"); 231 231 232 232 Next: number.put(c); 233 233 234 234 if(isdigit(peekChar())) { 235 235 c = getChar(); 236 236 goto Next; … … 303 303 } 304 304 305 305 parseValue(&root); 306 306 return root; 307 307 } 308 308 309 309 /** 310 310 Takes a tree of JSON values and returns the serialized string. 311 311 */ 312 312 string toJSON(in JSONValue* root) { 313 Appender!string json;313 auto json = appender!string(); 314 314 315 315 void toString(string str) { 316 316 json.put('"'); 317 317 318 318 foreach (dchar c; str) { 319 319 switch(c) { 320 320 case '"': json.put("\\\""); break; 321 321 case '\\': json.put("\\\\"); break; 322 322 case '/': json.put("\\/"); break; 323 323 case '\b': json.put("\\b"); break; trunk/phobos/std/process.d
r1725 r1733 309 309 { 310 310 result ~= line; 311 311 } 312 312 f.close; 313 313 return result; 314 314 } 315 315 316 316 version (Windows) string shell(string cmd) 317 317 { 318 318 // Generate a random filename 319 Appender!string a;319 auto a = appender!string(); 320 320 foreach (ref e; 0 .. 8) 321 321 { 322 322 formattedWrite(a, "%x", rndGen.front); 323 323 rndGen.popFront; 324 324 } 325 325 auto filename = a.data; 326 326 scope(exit) if (exists(filename)) remove(filename); 327 327 errnoEnforce(system(cmd ~ "> " ~ filename) == 0); 328 328 return readText(filename); 329 329 } trunk/phobos/std/regex.d
r1596 r1733 1710 1710 ---- 1711 1711 */ 1712 1712 public Captures captures() 1713 1713 { 1714 1714 return Captures(input, pmatch); 1715 1715 } 1716 1716 1717 1717 unittest 1718 1718 { 1719 1719 // @@@BUG@@@ This doesn't work if a client module uses -unittest 1720 // Appender!(char[]) app;1720 // auto app = appender!string(); 1721 1721 // foreach (m; match("abracadabra", "(.)a(.)")) 1722 1722 // { 1723 1723 // assert(m.captures.length == 3); 1724 1724 // foreach (c; m.captures) 1725 1725 // app.put(c), app.put(';'); 1726 1726 // } 1727 1727 // assert(app.data == "rac;r;c;dab;d;b;"); 1728 1728 } 1729 1729 1730 1730 /******************* … … 2997 2997 } 2998 2998 2999 2999 unittest 3000 3000 { 3001 3001 char[] s1 = ", abc, de, fg, hi, ".dup; 3002 3002 auto sp2 = splitter(s1, regex(", *")); 3003 3003 } 3004 3004 3005 3005 String[] split(String)(String input, Regex!(char) rx) 3006 3006 { 3007 Appender!(String[]) a;3007 auto a = appender!(String[])(); 3008 3008 foreach (e; splitter(input, rx)) 3009 3009 { 3010 3010 a.put(e); 3011 3011 } 3012 3012 return a.data; 3013 3013 } 3014 3014 3015 3015 unittest 3016 3016 { 3017 3017 auto s1 = ", abc, de, fg, hi, "; … … 3317 3317 assert(!match(to!(String)("a.B"), r).empty); 3318 3318 assert(!match(to!(String)("A.B"), r).empty); 3319 3319 assert(!match(to!(String)("a.b"), r).empty); 3320 3320 } 3321 3321 } 3322 3322 3323 3323 template loadFile(Types...) 3324 3324 { 3325 3325 Tuple!(Types)[] loadFile(Char)(string filename, Regex!(Char) rx) 3326 3326 { 3327 Appender!(typeof(return)) result;3327 auto result = appender!(typeof(return)); 3328 3328 auto f = File(filename); 3329 3329 scope(exit) f.close; 3330 3330 RegexMatch!(Char[]) match; 3331 3331 foreach (line; f.byLine()) 3332 3332 { 3333 3333 match = .match(line, rx); 3334 3334 Tuple!(Types) t; 3335 3335 foreach (i, unused; t.field) 3336 3336 { 3337 3337 t.field[i] = to!(typeof(t.field[i]))(match.captures[i + 1]); trunk/phobos/std/string.d
r1725 r1733 1317 1317 1318 1318 /************************************** 1319 1319 * Split s[] into an array of words, 1320 1320 * using delim[] as the delimiter. 1321 1321 */ 1322 1322 1323 1323 Unqual!(S1)[] split(S1, S2)(S1 s, S2 delim) 1324 1324 if (isSomeString!S1 && isSomeString!S2) 1325 1325 { 1326 1326 Unqual!(S1) us = s; 1327 auto app = Appender!(Unqual!(S1)[])();1327 auto app = appender!(Unqual!(S1)[])(); 1328 1328 foreach (word; std.algorithm.splitter(us, delim)) 1329 1329 { 1330 1330 app.put(word); 1331 1331 } 1332 1332 return app.data; 1333 1333 } 1334 1334 1335 1335 unittest 1336 1336 { 1337 1337 debug(string) printf("string.split2\n"); … … 1401 1401 1402 1402 /************************************** 1403 1403 * Split s[] into an array of lines, 1404 1404 * using CR, LF, or CR-LF as the delimiter. 1405 1405 * The delimiter is not included in the line. 1406 1406 */ 1407 1407 1408 1408 S[] splitlines(S)(S s) 1409 1409 { 1410 1410 size_t istart; 1411 auto result = Appender!(S[])();1411 auto result = appender!(S[])(); 1412 1412 1413 1413 foreach (i; 0 .. s.length) 1414 1414 { 1415 1415 immutable c = s[i]; 1416 1416 if (c == '\r' || c == '\n') 1417 1417 { 1418 1418 result.put(s[istart .. i]); 1419 1419 istart = i + 1; 1420 1420 if (c == '\r' && i + 1 < s.length && s[i + 1] == '\n') 1421 1421 { trunk/phobos/std/xml.d
r1552 r1733 342 342 * 343 343 * Examples: 344 344 * -------------- 345 345 * writefln(encode("a > b")); // writes "a > b" 346 346 * -------------- 347 347 */ 348 348 S encode(S)(S s, S buffer = null) 349 349 { 350 350 string r; 351 351 size_t lastI; 352 if (buffer ) buffer.length = 0;353 auto result = appender(&buffer);352 if (buffer.length) buffer.length = 0; 353 Appender!S result; 354 354 355 355 foreach (i, c; s) 356 356 { 357 357 switch (c) 358 358 { 359 359 case '&': r = "&"; break; 360 360 case '"': r = """; break; 361 361 case '\'': r = "'"; break; 362 362 case '<': r = "<"; break; 363 363 case '>': r = ">"; break; 364 364 default: continue; 365 365 } 366 366 // Replace with r 367 if (!result.data) 368 { 369 result = appender(&buffer); 370 } 367 371 result.put(s[lastI .. i]); 368 372 result.put(r); 369 373 lastI = i + 1; 370 374 } 371 375 372 376 if (!result.data) return s; 373 377 result.put(s[lastI .. $]); 374 378 return result.data; 375 379 } 376 380
