digitalmars.D.learn - Task to throw away string parts, use joiner and splitter not very
- Dfr (20/20) Dec 31 2013 Hello, i have string like "this.is.a.string" and want to throw
- Chris Cain (5/25) Dec 31 2013 From your error message: isForwardRange!Separator
- =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= (23/53) Dec 31 2013 As Chris wrote, using double quotes to use strings instead of char
- Dfr (8/67) Dec 31 2013 This is interesting, why i can't just do it simpler way ?
- =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= (3/71) Jan 01 2014 The popBack function returns the element you are removing from the
- monarch_dodra (6/21) Jan 02 2014 That's a function in "std.range": dropBack. No need for this.
- bearophile (5/9) Dec 31 2013 But splitting on a char is a common operation, and isn't it more
- monarch_dodra (7/17) Jan 02 2014 The "separator" here is actually a joiner element.
- Dfr (7/27) Dec 31 2013 And one more problem here:
- =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= (31/64) Jan 01 2014 You can use `std.conv.to` to convert the dchar[] back to a string,
- Dfr (2/75) Jan 01 2014
- monarch_dodra (4/10) Jan 02 2014 It's actually because "joiner" returns a range of dchar. It's
- monarch_dodra (62/74) Jan 02 2014 Pressed "sent" too soon. Anywas, as I was saying, joiner operates
Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.
Dec 31 2013
On Tuesday, 31 December 2013 at 20:49:55 UTC, Dfr wrote:Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.From your error message: isForwardRange!Separator Your separator is a character, which isn't a forward range. Try this: `auto name1 = joiner(nameparts[0 .. $-1], ".");`
Dec 31 2013
As Chris wrote, using double quotes to use strings instead of char solves the typing issse. I'd also suggest the following alternative, if you're going to discard a lot of last elements in your code: import std.stdio; import std.algorithm; import std.array; import std.range; /// Return seq without its last element. auto poppedBack (T) (T seq) if (isInputRange!T) { seq.popBack; // Discards the last element. return seq; } void main () { // Prints "this.is.a". "this.is.a.string" .splitter (".") .poppedBack .joiner (".") .array .writeln; } On 12/31/2013 09:57 PM, Chris Cain wrote:On Tuesday, 31 December 2013 at 20:49:55 UTC, Dfr wrote:Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.From your error message: isForwardRange!Separator Your separator is a character, which isn't a forward range. Try this: `auto name1 = joiner(nameparts[0 .. $-1], ".");`
Dec 31 2013
This is interesting, why i can't just do it simpler way ? "this.is.a.string" .splitter (".") .popBack .joiner (".") .array .writeln; Because creating an extra function is not desired.As Chris wrote, using double quotes to use strings instead of char solves the typing issse. I'd also suggest the following alternative, if you're going to discard a lot of last elements in your code: import std.stdio; import std.algorithm; import std.array; import std.range; /// Return seq without its last element. auto poppedBack (T) (T seq) if (isInputRange!T) { seq.popBack; // Discards the last element. return seq; } void main () { // Prints "this.is.a". "this.is.a.string" .splitter (".") .poppedBack .joiner (".") .array .writeln; } On 12/31/2013 09:57 PM, Chris Cain wrote:On Tuesday, 31 December 2013 at 20:49:55 UTC, Dfr wrote:Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.From your error message: isForwardRange!Separator Your separator is a character, which isn't a forward range. Try this: `auto name1 = joiner(nameparts[0 .. $-1], ".");`
Dec 31 2013
The popBack function returns the element you are removing from the array, not the array itself, thus "breaking" the chaining of function. On 01/01/2014 08:36 AM, Dfr wrote:This is interesting, why i can't just do it simpler way ? "this.is.a.string" .splitter (".") .popBack .joiner (".") .array .writeln; Because creating an extra function is not desired.As Chris wrote, using double quotes to use strings instead of char solves the typing issse. I'd also suggest the following alternative, if you're going to discard a lot of last elements in your code: import std.stdio; import std.algorithm; import std.array; import std.range; /// Return seq without its last element. auto poppedBack (T) (T seq) if (isInputRange!T) { seq.popBack; // Discards the last element. return seq; } void main () { // Prints "this.is.a". "this.is.a.string" .splitter (".") .poppedBack .joiner (".") .array .writeln; } On 12/31/2013 09:57 PM, Chris Cain wrote:On Tuesday, 31 December 2013 at 20:49:55 UTC, Dfr wrote:Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.From your error message: isForwardRange!Separator Your separator is a character, which isn't a forward range. Try this: `auto name1 = joiner(nameparts[0 .. $-1], ".");`
Jan 01 2014
On Tuesday, 31 December 2013 at 21:23:08 UTC, Rémy Mouëza wrote:I'd also suggest the following alternative, if you're going to discard a lot of last elements in your code: /// Return seq without its last element. auto poppedBack (T) (T seq) if (isInputRange!T) { seq.popBack; // Discards the last element. return seq; }That's a function in "std.range": dropBack. No need for this. On Wednesday, 1 January 2014 at 07:36:11 UTC, Dfr wrote:This is interesting, why i can't just do it simpler way ? "this.is.a.string" .splitter (".") .popBack .joiner (".") .array .writeln; Because creating an extra function is not desired.Because "popBack" is not the same as (the oddly named) "poppedBack". "drop" will do what you need, without a new function.
Jan 02 2014
Chris Cain:From your error message: isForwardRange!Separator Your separator is a character, which isn't a forward range. Try this: `auto name1 = joiner(nameparts[0 .. $-1], ".");`But splitting on a char is a common operation, and isn't it more efficient than splitting on a string? Bye, bearophile
Dec 31 2013
On Wednesday, 1 January 2014 at 00:19:39 UTC, bearophile wrote:Chris Cain:The "separator" here is actually a joiner element. "splitter(range, '.')" *does* work. AFAIK, there should be no problem providing a "joiner(RoR, E)". I think it's on my "todo". I think the "issue" was that the overload *may* have been ambiguous...? I'll have to double check.From your error message: isForwardRange!Separator Your separator is a character, which isn't a forward range. Try this: `auto name1 = joiner(nameparts[0 .. $-1], ".");`But splitting on a char is a common operation, and isn't it more efficient than splitting on a string? Bye, bearophile
Jan 02 2014
And one more problem here: string name = "test"; auto nameparts = splitter(name, '.'); writeln(typeof(joiner(nameparts, ".").array).stringof); This prints "dchar[]", but i need char[] or string, how to get my 'string' back ? On Tuesday, 31 December 2013 at 20:49:55 UTC, Dfr wrote:Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.
Dec 31 2013
You can use `std.conv.to` to convert the dchar[] back to a string, adding `.to!string` at the end of the dchar[] array you want to convert. Also not that there exists two similar functions to the lazy evaluated splitter() and joiner() in std.array: the eagerly evaluated split() and join(); being eager make the code looks more straightforward (no `.array` or `.to!string`). import std.stdio; import std.array; import std.algorithm; void eager () { string name = "thiš.ìs.à.çtriñg"; auto parts = name.split ("."); parts.popBack; auto cut = parts.join ("."); cut.writeln; } void lazy_ () { string name = "thiš.ìs.à.çtriñg"; auto parts = name.splitter ("."); parts.popBack; auto cut = parts.joiner (".").array.to!string; cut.writeln; } void main () { eager (); lazy_ (); } The program prints: thiš.ìs.à thiš.ìs.à On 01/01/2014 08:40 AM, Dfr wrote:And one more problem here: string name = "test"; auto nameparts = splitter(name, '.'); writeln(typeof(joiner(nameparts, ".").array).stringof); This prints "dchar[]", but i need char[] or string, how to get my 'string' back ? On Tuesday, 31 December 2013 at 20:49:55 UTC, Dfr wrote:Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.
Jan 01 2014
Thank you, very clear explained. On Wednesday, 1 January 2014 at 16:31:43 UTC, Rémy Mouëza wrote:You can use `std.conv.to` to convert the dchar[] back to a string, adding `.to!string` at the end of the dchar[] array you want to convert. Also not that there exists two similar functions to the lazy evaluated splitter() and joiner() in std.array: the eagerly evaluated split() and join(); being eager make the code looks more straightforward (no `.array` or `.to!string`). import std.stdio; import std.array; import std.algorithm; void eager () { string name = "thiš.ìs.à.çtriñg"; auto parts = name.split ("."); parts.popBack; auto cut = parts.join ("."); cut.writeln; } void lazy_ () { string name = "thiš.ìs.à.çtriñg"; auto parts = name.splitter ("."); parts.popBack; auto cut = parts.joiner (".").array.to!string; cut.writeln; } void main () { eager (); lazy_ (); } The program prints: thiš.ìs.à thiš.ìs.à On 01/01/2014 08:40 AM, Dfr wrote:And one more problem here: string name = "test"; auto nameparts = splitter(name, '.'); writeln(typeof(joiner(nameparts, ".").array).stringof); This prints "dchar[]", but i need char[] or string, how to get my 'string' back ? On Tuesday, 31 December 2013 at 20:49:55 UTC, Dfr wrote:Hello, i have string like "this.is.a.string" and want to throw away some parts separated by dots, here is first attempt: name = "this.is.a.string"; // <-- want to make "this.is.a" from this auto nameparts = splitter(name, '.'); auto name1 = joiner(nameparts[0 .. $-1], '.'); And got this error: "Error: Result cannot be sliced with []" So, kinda fixed it (correct way?): name = "this.is.a.string"; auto nameparts = splitter(name, '.').array; auto name1 = joiner(nameparts[0 .. $-1], '.'); got this: Error: template std.algorithm.joiner does not match any function template declaration. Candidates are: /usr/include/dmd/phobos/std/algorithm.d(2846): std.algorithm.joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) Stuck here, thank you for any help.
Jan 01 2014
On Wednesday, 1 January 2014 at 07:40:40 UTC, Dfr wrote:And one more problem here: string name = "test"; auto nameparts = splitter(name, '.'); writeln(typeof(joiner(nameparts, ".").array).stringof); This prints "dchar[]", but i need char[] or string, how to get my 'string' back ?It's actually because "joiner" returns a range of dchar. It's kind of inefficient actually. If you instead write a minimal "RangeJoiner", you can get:
Jan 02 2014
On Thursday, 2 January 2014 at 15:50:10 UTC, monarch_dodra wrote:On Wednesday, 1 January 2014 at 07:40:40 UTC, Dfr wrote:Pressed "sent" too soon. Anywas, as I was saying, joiner operates on RoR, so will return elements (dchar) individually. You *could* do a bit better with a "simpleJoiner", which will return strings at once: //---- auto simpleJoiner(R, E)(R r, E e) if (isInputRange!R && is(CommonType!(E, ElementType!R))) { static struct Result { private alias ElementType = CommonType!(E, .ElementType!R); private R r; private E e; private bool re = true; bool empty() property { return r.empty; } ElementType front() property { return re ? r.front : e; } void popFront() { if (re) r.popFront(); re = !re; } static if (isForwardRange!R) Result save() property { return Result(r.save, e); } } return Result(r, e); } //---- Using this will produce "string at once" elements, rather than dchars at once, which is a bit more efficient. It can also help depending on how you want to "visualize" the data you are handling. Also note, if all you want to do is print, there is no reason at all call "array", simply format your range with "%-(%s%)": //---- void main() { writefln("%-(%s%)", "this.is.a.test" .splitter('.') .dropBack(1) .joiner(".") //or simpleJoiner(".") ); } //---- In both case, it'll produce: //---- this.is.a //---- If you want to know, "%(" and "%)" means "range-mode-print. The %s inside is the individual element format, and "%-(" means "natural" print. Read more about it here: http://dlang.org/phobos/std_format.htmlAnd one more problem here: string name = "test"; auto nameparts = splitter(name, '.'); writeln(typeof(joiner(nameparts, ".").array).stringof); This prints "dchar[]", but i need char[] or string, how to get my 'string' back ?It's actually because "joiner" returns a range of dchar. It's kind of inefficient actually. If you instead write a minimal "RangeJoiner", you can get:
Jan 02 2014