www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Need help: Return reference slice

reply "advibm" <me notavalidmail.com> writes:
Hello,

I would like to create a D function that returns a slice of a 
string.
This slice shall be a reference to a part of the string argument.
Is this generally possible in D?

This is the function:
auto ref betweenTwoStrings(T)(inout T src, string start, string 
end) {
   long a = src.countUntil(start);
   if (a < 0)
     return src; // null
   a += start.length;
   long b = src[a..$].countUntil(end);
   if (b < 0)
     return src; // null
   b += a;
   return src[a..b];
}


I would like to have something like that:

char[] buf; // already filled array
char[] partOfBuf = betweenTwoStrings(buf, "START", "END");
partOfBuf[0] = 'a'; // THIS should also change the 'buf' variable
assert(buf[0] == 'a');

Thanks for your help
Oct 29 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
advibm:

 I would like to have something like that:

 char[] buf; // already filled array
 char[] partOfBuf = betweenTwoStrings(buf, "START", "END");
 partOfBuf[0] = 'a'; // THIS should also change the 'buf' 
 variable
 assert(buf[0] == 'a');

 Thanks for your help
To do this you don't need to return a ref slice. A slice suffices. But D strings/wstrings/dstrings are made of immutable chars, so you can't modify them. So you need to work with char[] or dchar[] or wchar[]. Bye, bearophile
Oct 29 2014
parent "advibm" <me notavalidmail.com> writes:
On Wednesday, 29 October 2014 at 19:54:45 UTC, bearophile wrote:
 advibm:

 I would like to have something like that:

 char[] buf; // already filled array
 char[] partOfBuf = betweenTwoStrings(buf, "START", "END");
 partOfBuf[0] = 'a'; // THIS should also change the 'buf' 
 variable
 assert(buf[0] == 'a');

 Thanks for your help
To do this you don't need to return a ref slice. A slice suffices. But D strings/wstrings/dstrings are made of immutable chars, so you can't modify them. So you need to work with char[] or dchar[] or wchar[]. Bye, bearophile
Thank you for your fast answer. I am embarrased but my code already works as expected. I made a mistake when I wanted to change the partOfBuf variable. I wrote: partOfBuf = replacedArray; But I had to write partOfBuf[0..$] = replacedArray.
Oct 29 2014
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 10/29/2014 12:50 PM, advibm wrote:
 Hello,

 I would like to create a D function that returns a slice of a string.
 This slice shall be a reference to a part of the string argument.
 Is this generally possible in D?

 This is the function:
 auto ref betweenTwoStrings(T)(inout T src, string start, string end) {
    long a = src.countUntil(start);
    if (a < 0)
      return src; // null
    a += start.length;
    long b = src[a..$].countUntil(end);
    if (b < 0)
      return src; // null
    b += a;
    return src[a..b];
 }


 I would like to have something like that:

 char[] buf; // already filled array
 char[] partOfBuf = betweenTwoStrings(buf, "START", "END");
 partOfBuf[0] = 'a'; // THIS should also change the 'buf' variable
 assert(buf[0] == 'a');

 Thanks for your help
There are pretty useful std.algorithm functions for searching: import std.algorithm; import std.traits; import std.array; C[] betweenTwoStrings(C)(C[] src, string start, string end) if (isSomeChar!C) { if (src.findSkip(start)) { auto found = src.findSplitBefore(end); // Just for readability: auto needleAndAfter = found[1]; if (!needleAndAfter.empty) { auto beforeNeedle = found[0]; return beforeNeedle; } } return (C[]).init; } void main() { char[] buf; buf ~= "prefixSTARTactual partENDpostfix"; char[] partOfBuf = betweenTwoStrings(buf, "START", "END"); partOfBuf[] = 'a'; assert(buf == "prefixSTARTaaaaaaaaaaaENDpostfix"); } Ali
Oct 29 2014
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/29/14 3:50 PM, advibm wrote:
 Hello,

 I would like to create a D function that returns a slice of a string.
 This slice shall be a reference to a part of the string argument.
 Is this generally possible in D?

 This is the function:
 auto ref betweenTwoStrings(T)(inout T src, string start, string end) {
    long a = src.countUntil(start);
    if (a < 0)
      return src; // null
    a += start.length;
    long b = src[a..$].countUntil(end);
    if (b < 0)
      return src; // null
    b += a;
    return src[a..b];
 }


 I would like to have something like that:

 char[] buf; // already filled array
 char[] partOfBuf = betweenTwoStrings(buf, "START", "END");
 partOfBuf[0] = 'a'; // THIS should also change the 'buf' variable
 assert(buf[0] == 'a');

 Thanks for your help
How I would do it: inout(T)[] betweenTwoStrings(T, U, V)(inout(T)[] src, const(U)[] start, const(V)[] end) if(allSatisfy!(isSomeChar, T, U, V)) { long a = src.countUntil(start); if (a < 0) return src; // null a += start.length; long b = src[a..$].countUntil(end); if (b < 0) return src; // null b += a; return src[a..b]; } This should accept any kind of strings, in any constancy for all the parameters, yet guarantee it does not change any data in any of them. -Steve.
Oct 30 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:

   long a = src.countUntil(start);
   if (a < 0)
     return src; // null
   a += start.length;
   long b = src[a..$].countUntil(end);
I think there it's better to use "auto" instead of "long". Bye, bearophile
Oct 30 2014
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/30/14 11:06 AM, bearophile wrote:
 Steven Schveighoffer:

   long a = src.countUntil(start);
   if (a < 0)
     return src; // null
   a += start.length;
   long b = src[a..$].countUntil(end);
I think there it's better to use "auto" instead of "long".
Sure, I didn't touch OP's function body, just the signature. -Steve
Oct 30 2014
prev sibling parent "advibm" <me notavalidmail.com> writes:
Thank you very much for your additions.
I am still new to D so I am glad to see solutions from 
experienced D programmers.
Oct 30 2014