www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Stride

reply RenatoL <rexlen gmail.com> writes:
Loosing my time on skittles...

input "abcd"
desired output "arcd"
i want to use stride

snippet, where x and y are integer in real code:

    string s1 = "abcd";
    s1 = s1[stride(s1,x)..y] ~ 'r' ~ s1[2..$];

if x = 0 and y = 0 -> run time error. ok
if x = 0 and y = 1 -> "rcd" (??)
if x = 1 and y = 0 -> run time error. ok
if x = 1 and y = 1 -> "rcd"
if x = 0 and y = 2 -> "brcd" (WTF?)
if x = 1 and y = 2 -> "brcd" (...)

what the hell of parameters have i to put to achieve "arcd"?
Feb 12 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/12/2012 09:37 AM, RenatoL wrote:
 Loosing my time on skittles...

 input "abcd"
 desired output "arcd"
 i want to use stride

 snippet, where x and y are integer in real code:

      string s1 = "abcd";
      s1 = s1[stride(s1,x)..y] ~ 'r' ~ s1[2..$];

 if x = 0 and y = 0 ->  run time error. ok
 if x = 0 and y = 1 ->  "rcd" (??)
 if x = 1 and y = 0 ->  run time error. ok
 if x = 1 and y = 1 ->  "rcd"
 if x = 0 and y = 2 ->  "brcd" (WTF?)
 if x = 1 and y = 2 ->  "brcd" (...)

 what the hell of parameters have i to put to achieve "arcd"?

This is yet another problem caused by the dual nature of narrow strings. When used with algorithms like stride(), a char[] is *not* a RandomAccessRange but when used with the [] operator it is. According the stride()'s documentation, s1 will lose elements through popFront() because of not being a RandomAccessRange. Related question: Does D define the order of evaluation in an expression like foo() ~ bar() Or is it unspecified as in C and C++? Ali
Feb 12 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/12/2012 10:07 AM, Ali Çehreli wrote:
 On 02/12/2012 09:37 AM, RenatoL wrote:
  > Loosing my time on skittles...
  >
  > input "abcd"
  > desired output "arcd"
  > i want to use stride
  >
  > snippet, where x and y are integer in real code:
  >
  > string s1 = "abcd";
  > s1 = s1[stride(s1,x)..y] ~ 'r' ~ s1[2..$];

No matter how much *my* explanation below still makes sense to *me*, :p I can't compile that code with dmd 2.057. (?)
  >
  > if x = 0 and y = 0 -> run time error. ok
  > if x = 0 and y = 1 -> "rcd" (??)
  > if x = 1 and y = 0 -> run time error. ok
  > if x = 1 and y = 1 -> "rcd"
  > if x = 0 and y = 2 -> "brcd" (WTF?)
  > if x = 1 and y = 2 -> "brcd" (...)
  >
  > what the hell of parameters have i to put to achieve "arcd"?

 This is yet another problem caused by the dual nature of narrow strings.
 When used with algorithms like stride(), a char[] is *not* a
 RandomAccessRange but when used with the [] operator it is.

 According the stride()'s documentation, s1 will lose elements through
 popFront() because of not being a RandomAccessRange.

 Related question: Does D define the order of evaluation in an expression
 like

 foo() ~ bar()

 Or is it unspecified as in C and C++?

 Ali

Ali
Feb 12 2012
parent reply RenatoL <rexlen gmail.com> writes:
This is the code i compiled v. 2057 and parameters 0 1
import std.stdio;
import std.utf;
void main()
{
    string s1 = "abcd";
    s1 = s1[stride(s1,0)..1] ~ 'r' ~ s1[2..$];
    writeln(s1);
}
Feb 12 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/12/2012 10:25 AM, RenatoL wrote:
 This is the code i compiled v. 2057 and parameters 0 1
 import std.stdio;
 import std.utf;
 void main()
 {
      string s1 = "abcd";
      s1 = s1[stride(s1,0)..1] ~ 'r' ~ s1[2..$];
      writeln(s1);
 }

Argh! std.algorithm.stride() and std.utf.stride() are different. :) What a confusion! :( I think the following is correct for the first part, but the 2 in the last part will also be wrong unless it is also calculated: s1 = s1[0..stride(s1,0)] ~ 'r' ~ s1[2..$]; Ali
Feb 12 2012
parent reply RenatoL <rexlen gmail.com> writes:
Mmmm.... this doesn't compile....

import std.stdio;
import std.algorithm;
void main()
{
    string s1 = "abcd";
    s1 = s1[stride(s1,0)..1] ~ 'r' ~ s1[2..$];
    writeln(s1);
}

Error: undefined identifier stride, did you mean alias string?
Feb 12 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/12/2012 11:05 AM, RenatoL wrote:
 Mmmm.... this doesn't compile....

 import std.stdio;
 import std.algorithm;
 void main()
 {
      string s1 = "abcd";
      s1 = s1[stride(s1,0)..1] ~ 'r' ~ s1[2..$];
      writeln(s1);
 }

 Error: undefined identifier stride, did you mean alias string?

Because I am not operating correctly lately. :( I meant std.range, not std.algorithm. But std.range.stride will cause a different compilation error because it returns a range object, not an index. Ali
Feb 12 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Sunday, February 12, 2012 10:07:52 Ali Çehreli wrote:
 Related question: Does D define the order of evaluation in an expression
 like
 
 foo() ~ bar()
 
 Or is it unspecified as in C and C++?

It's currently unspecified. Walter has stated that he wants to make it so that it's always left to right, but I don't believe that he's done it yet, and it may or may not ever happen. - Jonathan m Davis
Feb 13 2012
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 02/13/12 18:57, Jonathan M Davis wrote:
 On Sunday, February 12, 2012 10:07:52 Ali Çehreli wrote:
 Related question: Does D define the order of evaluation in an expression
 like

 foo() ~ bar()

 Or is it unspecified as in C and C++?

It's currently unspecified. Walter has stated that he wants to make it so that it's always left to right, but I don't believe that he's done it yet, and it may or may not ever happen.

Actually, it *is* specified as left-to-right, except for assignments and argument evaluation. http://dlang.org/expression.html No idea if the compiler fully implements that part of the spec. artur
Feb 13 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, February 13, 2012 19:47:03 Artur Skawina wrote:
 On 02/13/12 18:57, Jonathan M Davis wrote:
 On Sunday, February 12, 2012 10:07:52 Ali Çehreli wrote:
 Related question: Does D define the order of evaluation in an
 expression
 like
 
 foo() ~ bar()
 
 Or is it unspecified as in C and C++?

It's currently unspecified. Walter has stated that he wants to make it so that it's always left to right, but I don't believe that he's done it yet, and it may or may not ever happen.

Actually, it *is* specified as left-to-right, except for assignments and argument evaluation. http://dlang.org/expression.html No idea if the compiler fully implements that part of the spec.

Well, foo() ~ bar() _is_ argument evaluation if you're dealing with an overloaded operator. And unfortunately, whether the spec is what the compiler does is frequently suspect anyway. So, who knows. - Jonathan M Davis
Feb 13 2012
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 02/13/12 20:47, Jonathan M Davis wrote:
 On Monday, February 13, 2012 19:47:03 Artur Skawina wrote:
 On 02/13/12 18:57, Jonathan M Davis wrote:
 On Sunday, February 12, 2012 10:07:52 Ali Çehreli wrote:
 Related question: Does D define the order of evaluation in an
 expression
 like

 foo() ~ bar()

 Or is it unspecified as in C and C++?

It's currently unspecified. Walter has stated that he wants to make it so that it's always left to right, but I don't believe that he's done it yet, and it may or may not ever happen.

Actually, it *is* specified as left-to-right, except for assignments and argument evaluation. http://dlang.org/expression.html No idea if the compiler fully implements that part of the spec.

Well, foo() ~ bar() _is_ argument evaluation if you're dealing with an overloaded operator. And unfortunately, whether the spec is what the compiler does is frequently suspect anyway. So, who knows.

"argument evaluation" in this context means that given eg "f(a,b,c);" it's not specified in what order the expressions 'a', 'b', and 'c' are evaluated, which matters if they are dependent or have side effects. (depending on arg passing conventions it can make sense to implement this one way or the other). If an expression is specced as l-t-r (as CatExpression is here) then the call to foo() must happen before executing bar(); the operator only comes into play later. artur
Feb 13 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, February 13, 2012 21:49:05 Artur Skawina wrote:
 "argument evaluation" in this context means that given eg "f(a,b,c);"
 it's not specified in what order the expressions 'a', 'b', and 'c'
 are evaluated, which matters if they are dependent or have side
 effects. (depending on arg passing conventions it can make sense to
 implement this one way or the other). If an expression is specced
 as l-t-r (as CatExpression is here) then the call to foo() must
 happen before executing bar(); the operator only comes into play later.

Ideally perhaps, but I expect that that's not true, because operator overloading is done via lowering. foo() ~ bar() would become opBinary!"~"(foo(), bar()); which is a normal function call. It's possible that the compiler always evaluates foo first, but I'd seriously advise against relying on it. In the long run, it probably will be guaranteed, because Walter wants to make it so that function arguments are always evaluated left-to-right, but until that happens, I wouldn't bet on foo() ~ bar() being guaranteed to have foo called before bar, even it's supposed to be. - Jonathan M Davis
Feb 13 2012
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Jonathan M Davis" <jmdavisProg gmx.com> wrote in message 
news:mailman.306.1329166430.20196.digitalmars-d-learn puremagic.com...
 Ideally perhaps, but I expect that that's not true, because operator
 overloading is done via lowering.

 foo() ~ bar()

 would become

 opBinary!"~"(foo(), bar());

While your point is still correct, this will generally be lowered to foo().opBinary!"~"(bar()) or bar().opBinaryRight!"~"(foo()) Both of which do have a defined order of evaluation.
Feb 14 2012
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 02/13/12 21:52, Jonathan M Davis wrote:
 On Monday, February 13, 2012 21:49:05 Artur Skawina wrote:
 "argument evaluation" in this context means that given eg "f(a,b,c);"
 it's not specified in what order the expressions 'a', 'b', and 'c'
 are evaluated, which matters if they are dependent or have side
 effects. (depending on arg passing conventions it can make sense to
 implement this one way or the other). If an expression is specced
 as l-t-r (as CatExpression is here) then the call to foo() must
 happen before executing bar(); the operator only comes into play later.

Ideally perhaps, but I expect that that's not true, because operator overloading is done via lowering. foo() ~ bar() would become opBinary!"~"(foo(), bar()); which is a normal function call. It's possible that the compiler always evaluates foo first, but I'd seriously advise against relying on it. In the long run, it probably will be guaranteed, because Walter wants to make it so that function arguments are always evaluated left-to-right, but until that happens, I wouldn't bet on foo() ~ bar() being guaranteed to have foo called before bar, even it's supposed to be.

The important thing here is - the order absolutely *must* be foo(), then bar(), what happens under the hood is completely irrelevant. The reason is simple - if this is not what happens then it's a serious compiler bug. And if you can't rely on the order then it just shouldn't be documented. The order /could/ be undefined, so specifying it means the programmer has to assume he/she /can/ count that the compiler follows it - otherwise defining it wouldn't make any sense. IOW having the order defined, but not implemented, causes bugs that wouldn't be there without such definition; hence one has to assume that it *is* implemented (modulo unknown compiler bugs of course). Undefining the order is a much better solution than suggesting that users should assume the compiler is broken. It can always be re-defined later, switching from defined to undefined is not as easy. artur
Feb 13 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, February 13, 2012 22:24:38 Artur Skawina wrote:
 The important thing here is - the order absolutely *must* be foo(), then
 bar(), what happens under the hood is completely irrelevant. The reason is
 simple - if this is not what happens then it's a serious compiler bug. And
 if you can't rely on the order then it just shouldn't be documented. The
 order /could/ be undefined, so specifying it means the programmer has to
 assume he/she /can/ count that the compiler follows it - otherwise defining
 it wouldn't make any sense.
 IOW having the order defined, but not implemented, causes bugs that wouldn't
 be there without such definition; hence one has to assume that it *is*
 implemented (modulo unknown compiler bugs of course).
 Undefining the order is a much better solution than suggesting that users
 should assume the compiler is broken. It can always be re-defined later,
 switching from defined to undefined is not as easy.

I'm not arguing that the order _shouldn't_ be defined and guaranteed. I'm just saying that I wouldn't trust the compiler to make such guarantees. If you find that bar gets evaluated before foo, then by all means, report it. But unless one of the dmd devs verifies in the code that it does indeed guarantee left-to- right evaluation of foo() ~ bar() even with operator overloading, I would consider it a bad idea to rely on it. Given that lowering is involved, I think that there's a high chance that the order is just as defined as directly calling op!"~"(foo(), bar()) would be. - Jonathan M Davis
Feb 13 2012
prev sibling next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 02/13/12 22:58, Jonathan M Davis wrote:
 On Monday, February 13, 2012 22:24:38 Artur Skawina wrote:
 The important thing here is - the order absolutely *must* be foo(), then
 bar(), what happens under the hood is completely irrelevant. The reason is
 simple - if this is not what happens then it's a serious compiler bug. And
 if you can't rely on the order then it just shouldn't be documented. The
 order /could/ be undefined, so specifying it means the programmer has to
 assume he/she /can/ count that the compiler follows it - otherwise defining
 it wouldn't make any sense.
 IOW having the order defined, but not implemented, causes bugs that wouldn't
 be there without such definition; hence one has to assume that it *is*
 implemented (modulo unknown compiler bugs of course).
 Undefining the order is a much better solution than suggesting that users
 should assume the compiler is broken. It can always be re-defined later,
 switching from defined to undefined is not as easy.

I'm not arguing that the order _shouldn't_ be defined and guaranteed. I'm just

I'm not arguing that it _should_ be defined - just pointing out that the fact that it currently _is_ means one should be able to assume it works. After all there's only one D frontend and it comes from the vendor that also effectively controls the language spec - so it's reasonable to expect things that are documented, but could have been omitted, to work. If the compiler does not currently implement these spec parts it would be much better to say that the order *will* be L-T-R, but right now is undefined. That way users won't be mislead and if somebody else decides do to a D compiler it will be clear what should happen. Switching later from L-T-R to Undefined breaks backwards compatibility, but doing it the other way is harmless. artur
Feb 13 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/13/2012 11:27 PM, Artur Skawina wrote:
 On 02/13/12 22:58, Jonathan M Davis wrote:
 On Monday, February 13, 2012 22:24:38 Artur Skawina wrote:
 The important thing here is - the order absolutely *must* be foo(), then
 bar(), what happens under the hood is completely irrelevant. The reason is
 simple - if this is not what happens then it's a serious compiler bug. And
 if you can't rely on the order then it just shouldn't be documented. The
 order /could/ be undefined, so specifying it means the programmer has to
 assume he/she /can/ count that the compiler follows it - otherwise defining
 it wouldn't make any sense.
 IOW having the order defined, but not implemented, causes bugs that wouldn't
 be there without such definition; hence one has to assume that it *is*
 implemented (modulo unknown compiler bugs of course).
 Undefining the order is a much better solution than suggesting that users
 should assume the compiler is broken. It can always be re-defined later,
 switching from defined to undefined is not as easy.

I'm not arguing that the order _shouldn't_ be defined and guaranteed. I'm just

I'm not arguing that it _should_ be defined - just pointing out that the fact that it currently _is_ means one should be able to assume it works. After all there's only one D frontend and it comes from the vendor that also effectively controls the language spec - so it's reasonable to expect things that are documented, but could have been omitted, to work. If the compiler does not currently implement these spec parts it would be much better to say that the order *will* be L-T-R, but right now is undefined. That way users won't be mislead and if somebody else decides do to a D compiler it will be clear what should happen. Switching later from L-T-R to Undefined breaks backwards compatibility, but doing it the other way is harmless. artur

D the language requires L-T-R for both binary operators and function invocation. If DMD the compiler does not implement this in all cases then that is a bug. Why should a compiler bug have any influence whatsoever on the *language specification* ? I cannot follow. Order of evaluation for assignment expressions seems to be undefined in DMD 2.057, the following code has differing behavior in presence or absence of the optimization flags: int foo(int x){writeln(x);return 0;} ref int bar(int a,int b,int c){return *(new int);} void main(){ bar(foo(0),foo(1),foo(2))=bar(foo(3),foo(4),foo(5)); } FWIW, I didn't find any other counter-examples.
Feb 13 2012
parent reply RenatoL <rexlen gmail.com> writes:
mmmhhh.... this is interesting nevertheless i don't understand the
solution of my problem, and i cannot even understand it's origin:

void main()
{
    string s1 = "abcd";
    s1 = s1[stride(s1,0)..1] ~ 'r' ~ s1[2..$];
    writeln(s1);
}

why there is not way i cannot achive "arcd"?
Feb 14 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/14/2012 12:59 PM, RenatoL wrote:
 mmmhhh.... this is interesting nevertheless i don't understand the
 solution of my problem, and i cannot even understand it's origin:

 void main()
 {
      string s1 = "abcd";
      s1 = s1[stride(s1,0)..1] ~ 'r' ~ s1[2..$];
      writeln(s1);
 }

 why there is not way i cannot achive "arcd"?

import std.stdio; import std.utf; void main() { string s1 = "abcd"; immutable firstCharStride = stride(s1, 0); immutable secondCharStride = stride(s1, firstCharStride); auto firstPart = s1[0..firstCharStride]; auto lastPart = s1[firstCharStride + secondCharStride..$]; s1 = firstPart ~ 'r' ~ lastPart; writeln(s1); } Ali
Feb 14 2012
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 02/13/12 23:39, Timon Gehr wrote:
 On 02/13/2012 11:27 PM, Artur Skawina wrote:
 On 02/13/12 22:58, Jonathan M Davis wrote:
 On Monday, February 13, 2012 22:24:38 Artur Skawina wrote:
 The important thing here is - the order absolutely *must* be foo(), then
 bar(), what happens under the hood is completely irrelevant. The reason is
 simple - if this is not what happens then it's a serious compiler bug. And
 if you can't rely on the order then it just shouldn't be documented. The
 order /could/ be undefined, so specifying it means the programmer has to
 assume he/she /can/ count that the compiler follows it - otherwise defining
 it wouldn't make any sense.
 IOW having the order defined, but not implemented, causes bugs that wouldn't
 be there without such definition; hence one has to assume that it *is*
 implemented (modulo unknown compiler bugs of course).
 Undefining the order is a much better solution than suggesting that users
 should assume the compiler is broken. It can always be re-defined later,
 switching from defined to undefined is not as easy.

I'm not arguing that the order _shouldn't_ be defined and guaranteed. I'm just

I'm not arguing that it _should_ be defined - just pointing out that the fact that it currently _is_ means one should be able to assume it works. After all there's only one D frontend and it comes from the vendor that also effectively controls the language spec - so it's reasonable to expect things that are documented, but could have been omitted, to work. If the compiler does not currently implement these spec parts it would be much better to say that the order *will* be L-T-R, but right now is undefined. That way users won't be mislead and if somebody else decides do to a D compiler it will be clear what should happen. Switching later from L-T-R to Undefined breaks backwards compatibility, but doing it the other way is harmless. artur

D the language requires L-T-R for both binary operators and function invocation. If DMD the compiler does not implement this in all cases then that is a bug. Why should a compiler bug have any influence whatsoever on the *language specification* ? I cannot follow.

In theory it shouldn't, but it's much better to have a situation where the spec can be incrementally improved, than to end up having to make backwards incompatible changes later, when for example it's found that fixing some corner cases would be too hard. And I keep saying that *if* the order is defined then it should be followed, otherwise it would be better to document the actual behavior; that's all. Is L-T-R for function arg evaluation documented somewhere, btw? The "expression" dlang.org page has it as implementation-defined. artur
Feb 13 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, February 13, 2012 23:27:37 Artur Skawina wrote:
 I'm not arguing that it _should_ be defined - just pointing out that the
 fact that it currently _is_ means one should be able to assume it works.
 After all there's only one D frontend and it comes from the vendor that
 also effectively controls the language spec - so it's reasonable to expect
 things that are documented, but could have been omitted, to work. If the
 compiler does not currently implement these spec parts it would be much
 better to say that the order *will* be L-T-R, but right now is undefined.
 That way users won't be mislead and if somebody else decides do to a D
 compiler it will be clear what should happen. Switching later from L-T-R to
 Undefined breaks backwards compatibility, but doing it the other way is
 harmless.

The reality of the matter is that the spec is untrustworthy. The compiler may or may not follow it, and just because the spec says something and the compiler doesn't agree doesn't mean that the spec is going to win out. It's better than it used to be, and I think that Walter fixed a number of things in it recently, but the spec is notorious for being out-of-date when it comes to the little details. In this particular case, I'd fully expect that the spec is correct and that if the compiler doesn't follow suit, then it's buggy. However, it's also the kind of situation where I think that a bug would be very likely. So, I'd advise against relying on it, simply because the odds of your code being buggy (due to what is likely a compiler bug) are too high. - Jonathan M Davis
Feb 13 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, February 15, 2012 17:32:07 Daniel Murphy wrote:
 "Jonathan M Davis" <jmdavisProg gmx.com> wrote in message
 news:mailman.306.1329166430.20196.digitalmars-d-learn puremagic.com...
 
 Ideally perhaps, but I expect that that's not true, because operator
 overloading is done via lowering.
 
 foo() ~ bar()
 
 would become
 
 opBinary!"~"(foo(), bar());

While your point is still correct, this will generally be lowered to foo().opBinary!"~"(bar()) or bar().opBinaryRight!"~"(foo()) Both of which do have a defined order of evaluation.

Ah, good point. - Jonathan M Davis
Feb 14 2012
prev sibling parent "Chris W." <wendlec cd.ie> writes:
On Tuesday, 14 February 2012 at 21:09:09 UTC, Ali Çehreli wrote:
 On 02/14/2012 12:59 PM, RenatoL wrote:
 mmmhhh.... this is interesting nevertheless i don't understand 
 the
 solution of my problem, and i cannot even understand it's 
 origin:

 void main()
 {
     string s1 = "abcd";
     s1 = s1[stride(s1,0)..1] ~ 'r' ~ s1[2..$];
     writeln(s1);
 }

 why there is not way i cannot achive "arcd"?

import std.stdio; import std.utf; void main() { string s1 = "abcd"; immutable firstCharStride = stride(s1, 0); immutable secondCharStride = stride(s1, firstCharStride); auto firstPart = s1[0..firstCharStride]; auto lastPart = s1[firstCharStride + secondCharStride..$]; s1 = firstPart ~ 'r' ~ lastPart; writeln(s1); } Ali

I have come across similar problems using stride. Andrei Alexandrescu writes in his book on D that it is a subtle bug, if strings are not sliced using stride(s, index). However, if index is the length of another string there might be a mismatch, because stride() returns the "number of bytes in the UTF-8/16/32 sequence" which may not correspond to length/the index needed. E.g. if you have a string "chat" and you want to slice it as follows: auto word = "chat"; // Do some regex search ... // m[0] is the matched start sequence "ch" auto substring = word[m[0].length..$]; // "at" Using stride() returns 1 and not 2 (length of "ch"), so you'd get "hat" instead of "at". To avoid this and keep it "legal", is it possible to determine a string's length with std.utf.count() to determine the length of a string via utf code points (or toUCSindex())? auto substring = word[std.utf.count(m[0])..$]; // "at"
Mar 14 2012