www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to use retro over findSplitBefore result?

reply "MrSmith" <mrsmith33 yandex.ru> writes:
I am trying to compile following code

import std.algorithm : findSplitBefore;
import std.range : retro;
import std.array : array;

// returns file path where name has suffix and prefix
string withSuffixPrefix(string filePath, string prefix, string 
suffix)
{
     auto splitted = filePath.retro.findSplitBefore("/");

     return cast(string)splitted[1].retro.array
		~ prefix
		~ cast(string)splitted[0].retro.array //Fails!
		~ suffix;
}

With following error:
build.d(56): Error: template std.range.retro does not match any 
function template declaration. Candidates are:
/phobos/std/range.d(1455):   std.range.retro(Range)(Range r) if 
(isBidirectionalRange!(Unqual!Range))
build.d(56): Error: template std.range.retro(Range)(Range r) if 
(isBidirectionalRange!(Unqual!Range)) cannot deduce template 
function from argument types !()(Result)

Seems like i need to somehow convert splitted[0] to Bidirectional 
range.

This function will be used like this:
assert(withSuffixPrefix("/some/random/path/to/file", "pref-", 
".fl") == "/some/random/path/to/pref-file.fl");
Dec 04 2013
next sibling parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Wednesday, 4 December 2013 at 17:43:22 UTC, MrSmith wrote:
 I am trying to compile following code

 import std.algorithm : findSplitBefore;
 import std.range : retro;
 import std.array : array;

 // returns file path where name has suffix and prefix
 string withSuffixPrefix(string filePath, string prefix, string 
 suffix)
 {
     auto splitted = filePath.retro.findSplitBefore("/");

     return cast(string)splitted[1].retro.array
 		~ prefix
 		~ cast(string)splitted[0].retro.array //Fails!
 		~ suffix;
 }
The casting you've placed in there scares me. The returned range is going to be of dchar, assuming you're interested in UTF support, you'll want a conversion not a cast, I recommend std.conv.to!string. But even this is too much so I've commented that out and replaced it with a somewhat lazy approach: import std.algorithm : findSplitBefore; import std.range : retro, chain; import std.array : array; import std.conv : to; // returns file path where name has suffix and prefix string withSuffixPrefix(string filePath, string prefix, string suffix) { auto splitted = filePath.retro.findSplitBefore("/"); //return splitted[1].array.retro.to!string // ~ prefix // ~ splitted[0].array.retro.to!string // ~ suffix; return chain(splitted[1].array.retro, prefix, splitted[0].array.retro, suffix).array; } void main() { assert(withSuffixPrefix("/some/random/path/to/file", "pref-", ".fl") == "/some/random/path/to/pref-file.fl"); }
Dec 04 2013
parent "MrSmith" <mrsmith33 yandex.ru> writes:
On Wednesday, 4 December 2013 at 18:01:52 UTC, Jesse Phillips 
wrote:
 On Wednesday, 4 December 2013 at 17:43:22 UTC, MrSmith wrote:
 I am trying to compile following code

 import std.algorithm : findSplitBefore;
 import std.range : retro;
 import std.array : array;

 // returns file path where name has suffix and prefix
 string withSuffixPrefix(string filePath, string prefix, string 
 suffix)
 {
    auto splitted = filePath.retro.findSplitBefore("/");

    return cast(string)splitted[1].retro.array
 		~ prefix
 		~ cast(string)splitted[0].retro.array //Fails!
 		~ suffix;
 }
The casting you've placed in there scares me. The returned range is going to be of dchar, assuming you're interested in UTF support, you'll want a conversion not a cast, I recommend std.conv.to!string. But even this is too much so I've commented that out and replaced it with a somewhat lazy approach: import std.algorithm : findSplitBefore; import std.range : retro, chain; import std.array : array; import std.conv : to; // returns file path where name has suffix and prefix string withSuffixPrefix(string filePath, string prefix, string suffix) { auto splitted = filePath.retro.findSplitBefore("/"); //return splitted[1].array.retro.to!string // ~ prefix // ~ splitted[0].array.retro.to!string // ~ suffix; return chain(splitted[1].array.retro, prefix, splitted[0].array.retro, suffix).array; } void main() { assert(withSuffixPrefix("/some/random/path/to/file", "pref-", ".fl") == "/some/random/path/to/pref-file.fl"); }
Thank you for help, it's working!
Dec 04 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/04/2013 09:43 AM, MrSmith wrote:
 I am trying to compile following code

 import std.algorithm : findSplitBefore;
 import std.range : retro;
 import std.array : array;

 // returns file path where name has suffix and prefix
 string withSuffixPrefix(string filePath, string prefix, string suffix)
 {
      auto splitted = filePath.retro.findSplitBefore("/");

      return cast(string)splitted[1].retro.array
          ~ prefix
          ~ cast(string)splitted[0].retro.array //Fails!
          ~ suffix;
 }

 With following error:
 build.d(56): Error: template std.range.retro does not match any function
 template declaration. Candidates are:
 /phobos/std/range.d(1455):   std.range.retro(Range)(Range r) if
 (isBidirectionalRange!(Unqual!Range))
 build.d(56): Error: template std.range.retro(Range)(Range r) if
 (isBidirectionalRange!(Unqual!Range)) cannot deduce template function
 from argument types !()(Result)

 Seems like i need to somehow convert splitted[0] to Bidirectional range.

 This function will be used like this:
 assert(withSuffixPrefix("/some/random/path/to/file", "pref-", ".fl") ==
 "/some/random/path/to/pref-file.fl");
The main reason is that the ranges that findSplitBefore produces are not BidirectionalRanges. retro requires a BidirectionalRange and for that reason splitted[0].retro fails. The following solution inserts an .array to produce a BidirectionalRange. However, I don't see any reason why findSplitBefore could not produce BidirectionalRanges when it operated on a BidirectionalRange to begin with. Just to stay with your algorithm, you can also use std.conv.text (as well as std.conv.to!string, which Jesse Phillips recomended): import std.algorithm : findSplitBefore; import std.range; import std.array : array; import std.stdio; import std.conv; // returns file path where name has suffix and prefix string withSuffixPrefix(string filePath, string prefix, string suffix) { auto splitted = filePath.retro.findSplitBefore("/"); static assert(!isBidirectionalRange!(typeof(splitted[0]))); return splitted[1].retro.text ~ prefix ~ splitted[0].array.retro.text ~ suffix; } void main() { writeln(withSuffixPrefix("/some/random/path/to/file", "pref-", ".fl")); } Alternatively, you can use std.path: import std.path; import std.string; string withSuffixPrefix(string filePath, string prefix, string suffix) { return format("%s/%s%s%s", filePath.dirName, prefix, filePath.baseName, suffix); } void main() { assert(withSuffixPrefix("/some/random/path/to/file", "pref-", ".fl") == "/some/random/path/to/pref-file.fl"); } Ali
Dec 04 2013
parent "MrSmith" <mrsmith33 yandex.ru> writes:
On Wednesday, 4 December 2013 at 18:26:43 UTC, Ali Çehreli wrote:
 On 12/04/2013 09:43 AM, MrSmith wrote:
 I am trying to compile following code

 import std.algorithm : findSplitBefore;
 import std.range : retro;
 import std.array : array;

 // returns file path where name has suffix and prefix
 string withSuffixPrefix(string filePath, string prefix, string 
 suffix)
 {
     auto splitted = filePath.retro.findSplitBefore("/");

     return cast(string)splitted[1].retro.array
         ~ prefix
         ~ cast(string)splitted[0].retro.array //Fails!
         ~ suffix;
 }

 With following error:
 build.d(56): Error: template std.range.retro does not match 
 any function
 template declaration. Candidates are:
 /phobos/std/range.d(1455):   std.range.retro(Range)(Range r) if
 (isBidirectionalRange!(Unqual!Range))
 build.d(56): Error: template std.range.retro(Range)(Range r) if
 (isBidirectionalRange!(Unqual!Range)) cannot deduce template 
 function
 from argument types !()(Result)

 Seems like i need to somehow convert splitted[0] to 
 Bidirectional range.

 This function will be used like this:
 assert(withSuffixPrefix("/some/random/path/to/file", "pref-", 
 ".fl") ==
 "/some/random/path/to/pref-file.fl");
The main reason is that the ranges that findSplitBefore produces are not BidirectionalRanges. retro requires a BidirectionalRange and for that reason splitted[0].retro fails. The following solution inserts an .array to produce a BidirectionalRange. However, I don't see any reason why findSplitBefore could not produce BidirectionalRanges when it operated on a BidirectionalRange to begin with. Just to stay with your algorithm, you can also use std.conv.text (as well as std.conv.to!string, which Jesse Phillips recomended): import std.algorithm : findSplitBefore; import std.range; import std.array : array; import std.stdio; import std.conv; // returns file path where name has suffix and prefix string withSuffixPrefix(string filePath, string prefix, string suffix) { auto splitted = filePath.retro.findSplitBefore("/"); static assert(!isBidirectionalRange!(typeof(splitted[0]))); return splitted[1].retro.text ~ prefix ~ splitted[0].array.retro.text ~ suffix; } void main() { writeln(withSuffixPrefix("/some/random/path/to/file", "pref-", ".fl")); } Alternatively, you can use std.path: import std.path; import std.string; string withSuffixPrefix(string filePath, string prefix, string suffix) { return format("%s/%s%s%s", filePath.dirName, prefix, filePath.baseName, suffix); } void main() { assert(withSuffixPrefix("/some/random/path/to/file", "pref-", ".fl") == "/some/random/path/to/pref-file.fl"); } Ali
Thanks Ali!
Dec 04 2013