www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Task to throw away string parts, use joiner and splitter not very

reply "Dfr" <deflexor yandex.ru> writes:
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
next sibling parent reply "Chris Cain" <clcain uncg.edu> writes:
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
next sibling parent reply =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= <remy.moueza gmail.com> writes:
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
next sibling parent reply "Dfr" <deflexor yandex.ru> writes:
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
parent =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= <remy.moueza gmail.com> writes:
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
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 1 January 2014 at 00:19:39 UTC, bearophile wrote:
 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
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.
Jan 02 2014
prev sibling parent reply "Dfr" <deflexor yandex.ru> writes:
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
next sibling parent reply =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= <remy.moueza gmail.com> writes:
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
parent "Dfr" <deflexor yandex.ru> writes:
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
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
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
parent "monarch_dodra" <monarchdodra gmail.com> writes:
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:
 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:
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.html
Jan 02 2014