Skip to content

Commit

Permalink
Merge pull request #3305 from WalterBright/range-chop
Browse files Browse the repository at this point in the history
Range-ify std.string.chop
  • Loading branch information
andralex committed May 22, 2015
2 parents a1e3944 + ae966fb commit 6402342
Showing 1 changed file with 93 additions and 8 deletions.
101 changes: 93 additions & 8 deletions std/string.d
Expand Up @@ -2091,6 +2091,9 @@ auto representation(Char)(Char[] s) @safe pure nothrow @nogc
*
* Returns:
* The capitalized string.
*
* See_Also:
* $(XREF uni, toCapitalized) for a lazy range version that doesn't allocate memory
*/
S capitalize(S)(S s) @trusted pure
if (isSomeString!S)
Expand Down Expand Up @@ -3059,19 +3062,67 @@ unittest
Returns $(D str) without its last character, if there is one. If $(D str)
ends with $(D "\r\n"), then both are removed. If $(D str) is empty, then
then it is returned unchanged.
Params:
str = string (must be valid UTF)
Returns:
slice of str
+/
S chop(S)(S str) @safe pure
if (isSomeString!S)

Range chop(Range)(Range str)
if (isSomeString!Range ||
isBidirectionalRange!Range && isSomeChar!(ElementEncodingType!Range))
{
if (str.empty)
return str;

if (str.length >= 2 && str[$ - 1] == '\n' && str[$ - 2] == '\r')
return str[0 .. $ - 2];

str.popBack();

return str;
static if (isSomeString!Range)
{
if (str.length >= 2 && str[$ - 1] == '\n' && str[$ - 2] == '\r')
return str[0 .. $ - 2];
str.popBack();
return str;
}
else
{
alias C = Unqual!(ElementEncodingType!Range);
C c = str.back;
str.popBack();
if (c == '\n')
{
if (!str.empty && str.back == '\r')
str.popBack();
return str;
}
// Pop back a dchar, not just a code unit
static if (C.sizeof == 1)
{
int cnt = 1;
while ((c & 0xC0) == 0x80)
{
if (str.empty)
break;
c = str.back;
str.popBack();
if (++cnt > 4)
break;
}
}
else static if (C.sizeof == 2)
{
if (c >= 0xD800 && c <= 0xDBFF)
{
if (!str.empty)
str.popBack();
}
}
else static if (C.sizeof == 4)
{
}
else
static assert(0);
return str;
}
}

///
Expand All @@ -3086,6 +3137,40 @@ S chop(S)(S str) @safe pure
assert(chop("") == "");
}

@safe pure unittest
{
import std.utf : byChar, byWchar, byDchar, byCodeUnit, invalidUTFstrings;
import std.array;

assert(chop("hello world".byChar).array == "hello worl");
assert(chop("hello world\n"w.byWchar).array == "hello world"w);
assert(chop("hello world\r"d.byDchar).array == "hello world"d);
assert(chop("hello world\n\r".byChar).array == "hello world\n");
assert(chop("hello world\r\n"w.byWchar).array == "hello world"w);
assert(chop("Walter Bright"d.byDchar).array == "Walter Brigh"d);
assert(chop("".byChar).array == "");

assert(chop(`ミツバチと科学者` .byCodeUnit).array == "ミツバチと科学");
assert(chop(`ミツバチと科学者`w.byCodeUnit).array == "ミツバチと科学"w);
assert(chop(`ミツバチと科学者`d.byCodeUnit).array == "ミツバチと科学"d);

auto ca = invalidUTFstrings!char();
foreach (s; ca)
{
foreach (c; chop(s.byCodeUnit))
{
}
}

auto wa = invalidUTFstrings!wchar();
foreach (s; wa)
{
foreach (c; chop(s.byCodeUnit))
{
}
}
}

unittest
{
import std.conv : to;
Expand Down

0 comments on commit 6402342

Please sign in to comment.