Thread overview
How to use retro over findSplitBefore result?
Dec 04, 2013
MrSmith
Dec 04, 2013
Jesse Phillips
Dec 04, 2013
MrSmith
Dec 04, 2013
Ali Çehreli
Dec 04, 2013
MrSmith
December 04, 2013
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");
December 04, 2013
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");
}
December 04, 2013
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

December 04, 2013
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!
December 04, 2013
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!