Skip to content

Commit 2f2dfbc

Browse files
committed
Fix issue 13632: Enhancement to std.string.strip
Added second argument similar to Python `str.strip` Second argument accepts list of chars to strip and strips only those chars. Examples: "xyzhello".stripLeft("xyz") == ""hello" "helloxy ".stripRight("xy ") == "hello" "xhellox".strip("x") == "hello" Signed-off-by: Aravinda VK <mail@aravindavk.in>
1 parent 6fe220f commit 2f2dfbc

File tree

1 file changed

+151
-1
lines changed

1 file changed

+151
-1
lines changed

std/string.d

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,36 @@ if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) &&
28552855
return input;
28562856
}
28572857

2858+
/++
2859+
Strips leading characters as specified in second argument.
2860+
2861+
Params:
2862+
input = string or $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
2863+
of characters
2864+
chars = list of chars to strip
2865+
2866+
Returns: $(D input) stripped of extra characters.
2867+
2868+
Postconditions: $(D input) and the returned value
2869+
will share the same tail (see $(REF sameTail, std,array)).
2870+
2871+
See_Also:
2872+
Generic stripping on ranges: $(REF _stripLeft, std, algorithm, mutation)
2873+
+/
2874+
auto stripLeft(Range)(Range input, string chars)
2875+
if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) &&
2876+
!isInfinite!Range && !isConvertibleToString!Range)
2877+
{
2878+
while (!input.empty)
2879+
{
2880+
auto c = input.front;
2881+
if (indexOf(chars, c) == -1)
2882+
break;
2883+
input.popFront();
2884+
}
2885+
return input;
2886+
}
2887+
28582888
///
28592889
@safe pure unittest
28602890
{
@@ -2870,10 +2900,24 @@ if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) &&
28702900
assert(stripLeft([paraSep] ~ "hello world" ~ paraSep) ==
28712901
"hello world" ~ [paraSep]);
28722902

2903+
assert(stripLeft(" hello world ", " ") ==
2904+
"hello world ");
2905+
assert(stripLeft("xxxxxhello world ", "x") ==
2906+
"hello world ");
2907+
assert(stripLeft("xxxyy hello world ", "xy ") ==
2908+
"hello world ");
2909+
28732910
import std.array : array;
2874-
import std.utf : byChar;
2911+
import std.utf : byChar, byWchar, byDchar;
28752912
assert(stripLeft(" hello world "w.byChar).array ==
28762913
"hello world ");
2914+
2915+
assert(stripLeft(" xxxyy hello world "w.byChar, "xy ").array ==
2916+
"hello world ");
2917+
2918+
assert(stripLeft("\u2028\u2020hello world\u2028"w.byWchar, "\u2028").array == "\u2020hello world\u2028");
2919+
assert(stripLeft("\U00010001hello world"w.byWchar, " ").array == "\U00010001hello world"w);
2920+
assert(stripLeft("\U00010001 xyhello world"d.byDchar, "\U00010001 xy").array == "hello world"d);
28772921
}
28782922

28792923
auto stripLeft(Range)(auto ref Range str)
@@ -2882,6 +2926,12 @@ if (isConvertibleToString!Range)
28822926
return stripLeft!(StringTypeOf!Range)(str);
28832927
}
28842928

2929+
auto stripLeft(Range)(auto ref Range str, string chars)
2930+
if (isConvertibleToString!Range)
2931+
{
2932+
return stripLeft!(StringTypeOf!Range)(str, chars);
2933+
}
2934+
28852935
@safe pure unittest
28862936
{
28872937
assert(testAliasedString!stripLeft(" hello"));
@@ -2995,6 +3045,53 @@ if (isSomeString!Range ||
29953045
}
29963046
}
29973047

3048+
/++
3049+
Strips trailing characters as specified in second argument.
3050+
3051+
Params:
3052+
str = string or random access range of characters
3053+
chars = list of chars to strip
3054+
3055+
Returns:
3056+
slice of $(D str) stripped of trailing extra characters.
3057+
3058+
See_Also:
3059+
Generic stripping on ranges: $(REF _stripRight, std, algorithm, mutation)
3060+
+/
3061+
auto stripRight(Range)(Range str, string chars)
3062+
if (isSomeString!Range ||
3063+
isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range &&
3064+
!isConvertibleToString!Range &&
3065+
isSomeChar!(ElementEncodingType!Range))
3066+
{
3067+
alias C = Unqual!(ElementEncodingType!(typeof(str)));
3068+
3069+
static if (isSomeString!(typeof(str)))
3070+
{
3071+
import std.utf : codeLength;
3072+
3073+
foreach_reverse (i, dchar c; str)
3074+
{
3075+
if (indexOf(chars, c) == -1)
3076+
return str[0 .. i + codeLength!C(c)];
3077+
}
3078+
3079+
return str[0 .. 0];
3080+
}
3081+
else
3082+
{
3083+
size_t i = str.length;
3084+
while (i--)
3085+
{
3086+
if (indexOf(chars, str[i]) != -1)
3087+
continue;
3088+
break;
3089+
}
3090+
3091+
return str[0 .. i + 1];
3092+
}
3093+
}
3094+
29983095
///
29993096
@safe pure
30003097
unittest
@@ -3010,6 +3107,13 @@ unittest
30103107
[lineSep] ~ "hello world");
30113108
assert(stripRight([paraSep] ~ "hello world" ~ paraSep) ==
30123109
[paraSep] ~ "hello world");
3110+
3111+
assert(stripRight(" hello world ", "x") ==
3112+
" hello world ");
3113+
assert(stripRight(" hello world ", " ") ==
3114+
" hello world");
3115+
assert(stripRight(" hello worldxy ", "xy ") ==
3116+
" hello world");
30133117
}
30143118

30153119
auto stripRight(Range)(auto ref Range str)
@@ -3018,6 +3122,12 @@ if (isConvertibleToString!Range)
30183122
return stripRight!(StringTypeOf!Range)(str);
30193123
}
30203124

3125+
auto stripRight(Range)(auto ref Range str, string chars)
3126+
if (isConvertibleToString!Range)
3127+
{
3128+
return stripRight!(StringTypeOf!Range)(str, chars);
3129+
}
3130+
30213131
@safe pure unittest
30223132
{
30233133
assert(testAliasedString!stripRight("hello "));
@@ -3045,6 +3155,11 @@ if (isConvertibleToString!Range)
30453155
cast(void) stripRight("a\x80".byUTF!char).array;
30463156
wstring ws = ['a', cast(wchar) 0xDC00];
30473157
cast(void) stripRight(ws.byUTF!wchar).array;
3158+
3159+
assert(stripRight(" hello world xyz ".byChar, "xyz ").array == " hello world");
3160+
assert(stripRight("\u2028hello world\u2020\u2028"w.byWchar, "\u2028").array == "\u2028hello world\u2020");
3161+
assert(stripRight("hello world\U00010001"w.byWchar, " ").array == "hello world\U00010001"w);
3162+
assert(stripRight("hello world\U00010001 xy"d.byDchar, "\U00010001 xy").array == "hello world"d);
30483163
}
30493164

30503165

@@ -3070,6 +3185,29 @@ if (isSomeString!Range ||
30703185
return stripRight(stripLeft(str));
30713186
}
30723187

3188+
/++
3189+
Strips both leading and trailing extra characters as specified in the
3190+
second argument.
3191+
3192+
Params:
3193+
str = string or random access range of characters
3194+
chars = list of chars to strip
3195+
3196+
Returns:
3197+
slice of $(D str) stripped of leading and trailing extra characters.
3198+
3199+
See_Also:
3200+
Generic stripping on ranges: $(REF _strip, std, algorithm, mutation)
3201+
+/
3202+
auto strip(Range)(Range str, string chars)
3203+
if (isSomeString!Range ||
3204+
isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range &&
3205+
!isConvertibleToString!Range &&
3206+
isSomeChar!(ElementEncodingType!Range))
3207+
{
3208+
return stripRight(stripLeft(str, chars), chars);
3209+
}
3210+
30733211
///
30743212
@safe pure unittest
30753213
{
@@ -3084,6 +3222,12 @@ if (isSomeString!Range ||
30843222
"hello world");
30853223
assert(strip([paraSep] ~ "hello world" ~ [paraSep]) ==
30863224
"hello world");
3225+
assert(strip(" hello world ", "x") ==
3226+
" hello world ");
3227+
assert(strip(" hello world ", " ") ==
3228+
"hello world");
3229+
assert(strip(" xyxyhello worldxyxy ", "xy ") ==
3230+
"hello world");
30873231
}
30883232

30893233
auto strip(Range)(auto ref Range str)
@@ -3092,6 +3236,12 @@ if (isConvertibleToString!Range)
30923236
return strip!(StringTypeOf!Range)(str);
30933237
}
30943238

3239+
auto strip(Range)(auto ref Range str, string chars)
3240+
if (isConvertibleToString!Range)
3241+
{
3242+
return strip!(StringTypeOf!Range)(str, chars);
3243+
}
3244+
30953245
@safe pure unittest
30963246
{
30973247
assert(testAliasedString!strip(" hello world "));

0 commit comments

Comments
 (0)