www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to extend the string class to return this inside the square

reply Marcone <marcone email.com> writes:
How to extend the string class to return this inside the square 
bracket the same way opDollar $ returns the length of the string? 
Thank you.

     import std;

     void main(){
     	writeln("Hello World!"[0..this.indexOf("o")]);
     }
Aug 13 2021
next sibling parent reply user1234 <user1234 12.de> writes:
On Friday, 13 August 2021 at 21:05:22 UTC, Marcone wrote:
 How to extend the string class to return this inside the square 
 bracket the same way opDollar $ returns the length of the 
 string? Thank you.

     import std;

     void main(){
     	writeln("Hello World!"[0..this.indexOf("o")]);
     }
this does not exist (and see few reason for) but algo + ufcs allows this easily, e.g ``` "Hello World!".findSplit("o")[0].writeln; ``` bonus: both can throw bound error
Aug 13 2021
parent Marcone <marcone email.com> writes:
On Friday, 13 August 2021 at 21:14:29 UTC, user1234 wrote:
 On Friday, 13 August 2021 at 21:05:22 UTC, Marcone wrote:
 How to extend the string class to return this inside the 
 square bracket the same way opDollar $ returns the length of 
 the string? Thank you.

     import std;

     void main(){
     	writeln("Hello World!"[0..this.indexOf("o")]);
     }
this does not exist (and see few reason for) but algo + ufcs allows this easily, e.g ``` "Hello World!".findSplit("o")[0].writeln; ``` bonus: both can throw bound error
My example was just an example. I don't want this solution. I want to have the power to handle the string inside the square brackets.
Aug 13 2021
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/13/21 5:05 PM, Marcone wrote:
 How to extend the string class to return this inside the square bracket 
 the same way opDollar $ returns the length of the string? Thank you.
 
      import std;
 
      void main(){
          writeln("Hello World!"[0..this.indexOf("o")]);
      }
There is no string class to extend. `$` is a special token the compiler changes to `arr.length` for arrays. -Steve
Aug 13 2021
parent reply Marcone <marcone email.com> writes:
On Friday, 13 August 2021 at 21:47:22 UTC, Steven Schveighoffer 
wrote:
 On 8/13/21 5:05 PM, Marcone wrote:
 How to extend the string class to return this inside the 
 square bracket the same way opDollar $ returns the length of 
 the string? Thank you.
 
      import std;
 
      void main(){
          writeln("Hello World!"[0..this.indexOf("o")]);
      }
There is no string class to extend. `$` is a special token the compiler changes to `arr.length` for arrays. -Steve
Isn't there some unario operator template that I can use with lambda to handle a string literal?
Aug 13 2021
parent reply jfondren <julian.fondren gmail.com> writes:
On Friday, 13 August 2021 at 22:09:59 UTC, Marcone wrote:
 Isn't there some unario operator template that I can use with 
 lambda to handle a string literal?
So, something other than an exact "lit"[0..this.xx(..)] syntax is fine? What didn't you like about `"Hello World!".findSplit("o")[0].writeln;` then? What is a real example of something you want to do?
Aug 13 2021
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/13/21 4:08 PM, jfondren wrote:
 On Friday, 13 August 2021 at 22:09:59 UTC, Marcone wrote:
 Isn't there some unario operator template that I can use with lambda 
 to handle a string literal?
So, something other than an exact "lit"[0..this.xx(..)] syntax is fine? What didn't you like about `"Hello World!".findSplit("o")[0].writeln;` then? What is a real example of something you want to do?
And I started writing the following but stopped because the semantics are not clear. I first called it 'between' but then should the 'o' that was searched be a part of the output? Should "from 'o' to 'o'" produce an empty string, should it include a single 'o' or should it go all the way to the next 'o'? What about the last line which says "from 'd' to 'a'"? Is that an entirely empty range or just 'd' or 'd' till the end? I don't think the programming language can decide one way or the other. import std.algorithm; import std.range; import std.stdio; auto inclusive(R, E)(R range, E fromNeedle, E toNeedle) { auto found = range.find(fromNeedle); return chain(found.front.only, found.drop(1).findSplitAfter(only(toNeedle))[0]); } void main() { const s = "Hello World!"; auto r = s.inclusive('o', 'o'); writeln(r); writeln("abcdef".inclusive('d', 'a')); } Ali
Aug 13 2021
parent Marcone <marcone email.com> writes:
On Friday, 13 August 2021 at 23:21:42 UTC, Ali Çehreli wrote:
 On 8/13/21 4:08 PM, jfondren wrote:
 On Friday, 13 August 2021 at 22:09:59 UTC, Marcone wrote:
 Isn't there some unario operator template that I can use with 
 lambda to handle a string literal?
So, something other than an exact "lit"[0..this.xx(..)] syntax is fine? What didn't you like about `"Hello World!".findSplit("o")[0].writeln;` then? What is a real example of something you want to do?
And I started writing the following but stopped because the semantics are not clear. I first called it 'between' but then should the 'o' that was searched be a part of the output? Should "from 'o' to 'o'" produce an empty string, should it include a single 'o' or should it go all the way to the next 'o'? What about the last line which says "from 'd' to 'a'"? Is that an entirely empty range or just 'd' or 'd' till the end? I don't think the programming language can decide one way or the other. import std.algorithm; import std.range; import std.stdio; auto inclusive(R, E)(R range, E fromNeedle, E toNeedle) { auto found = range.find(fromNeedle); return chain(found.front.only, found.drop(1).findSplitAfter(only(toNeedle))[0]); } void main() { const s = "Hello World!"; auto r = s.inclusive('o', 'o'); writeln(r); writeln("abcdef".inclusive('d', 'a')); } Ali
import std; class None {} // Function slice() auto slice(T1, T2, T3 = None)(T1 conteudo, T2 inicio, T3 fim = T3.init) { int start, end, startlen; static if (is(T2 == int)) {inicio = inicio < 0 ? conteudo.length + inicio : inicio;} static if (is(T3 == int)) {fim = fim <= 0 ? conteudo.length + fim : fim;} static if (is(T2 == int)) {start = inicio;} else static if (is(T2 == string)){start = conteudo.countUntil(inicio);} static if (is(T2 == string)) {static if (is(T1 == string)){startlen = start + inicio.length + 1;} else {startlen = start + 1;}} static if (is(T3 == int)) {end = fim;} else static if (is(T3 == string)){end = startlen + conteudo[startlen..$].countUntil(fim);} static if (is(T3 == None)) {return conteudo[start];} else {return conteudo[start..end];} } void main(){ writeln("Hello World!".slice(1, 8)); // ello Wo writeln("Hello World!".slice("e", "r")); // ello Wo writeln("Hello World!".slice(1, "r")); // ello Wo writeln("Hello World!".slice("e", 8)); // ello Wo writeln("Hello World!".slice(6, -1)); // World (Same as $-1) writeln("Hello World!".slice(-12, -7)); // Hello (Same as $-12, $-7) writeln("Hello World!".slice("W", -1)); // World (Same as "W", $-1) writeln("Hello World!".slice(-12, " ")); // Hello (Same as $-12, " ") } Like this function, but inside []. So I can use functions to get index for slice.
Aug 13 2021
prev sibling parent reply Marcone <marcone email.com> writes:
On Friday, 13 August 2021 at 23:08:07 UTC, jfondren wrote:
 On Friday, 13 August 2021 at 22:09:59 UTC, Marcone wrote:
 Isn't there some unario operator template that I can use with 
 lambda to handle a string literal?
So, something other than an exact "lit"[0..this.xx(..)] syntax is fine? What didn't you like about `"Hello World!".findSplit("o")[0].writeln;` then? What is a real example of something you want to do?
writeln("Hello World!"[x.indexOf("e")..x.indexOf("r")]); indexOf()is just a simple example, not the goal. I want handle literal inside [] like it bellow, but in literal: string x = "Hello World!"; writeln(x[x.indexOf("e")..x.indexOf("r")]);
Aug 13 2021
next sibling parent jfondren <julian.fondren gmail.com> writes:
On Friday, 13 August 2021 at 23:23:55 UTC, Marcone wrote:
 On Friday, 13 August 2021 at 23:08:07 UTC, jfondren wrote:
 On Friday, 13 August 2021 at 22:09:59 UTC, Marcone wrote:
 Isn't there some unario operator template that I can use with 
 lambda to handle a string literal?
So, something other than an exact "lit"[0..this.xx(..)] syntax is fine? What didn't you like about `"Hello World!".findSplit("o")[0].writeln;` then? What is a real example of something you want to do?
writeln("Hello World!"[x.indexOf("e")..x.indexOf("r")]); indexOf()is just a simple example, not the goal. I want handle literal inside [] like it bellow, but in literal: string x = "Hello World!"; writeln(x[x.indexOf("e")..x.indexOf("r")]);
```d unittest { import std.functional : pipe; import std.string : indexOf; assert("Hello, world!".pipe!(x => x[x.indexOf("e") .. x.indexOf("r")]) == "ello, wo"); } ```
Aug 13 2021
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 13 August 2021 at 23:23:55 UTC, Marcone wrote:
 writeln("Hello World!"[x.indexOf("e")..x.indexOf("r")]);

 indexOf()is just a simple example, not the goal. I want handle 
 literal inside [] like it bellow, but in literal:

 string x = "Hello World!";
 writeln(x[x.indexOf("e")..x.indexOf("r")]);
You can use the `pipe` function to bind an arbitrary expression to a variable: ```d import std.functional: pipe; import std.algorithm: countUntil; import std.stdio: writeln; "Hello world!" .pipe!(s => s[s.countUntil('e') .. s.countUntil('r')]) .writeln; ```
Aug 13 2021
parent reply user1234 <user1234 12.de> writes:
On Friday, 13 August 2021 at 23:33:05 UTC, Paul Backus wrote:
 On Friday, 13 August 2021 at 23:23:55 UTC, Marcone wrote:
 writeln("Hello World!"[x.indexOf("e")..x.indexOf("r")]);

 indexOf()is just a simple example, not the goal. I want handle 
 literal inside [] like it bellow, but in literal:

 string x = "Hello World!";
 writeln(x[x.indexOf("e")..x.indexOf("r")]);
You can use the `pipe` function to bind an arbitrary expression to a variable: ```d import std.functional: pipe; import std.algorithm: countUntil; import std.stdio: writeln; "Hello world!" .pipe!(s => s[s.countUntil('e') .. s.countUntil('r')]) .writeln; ```
nice, that's the best alternative.
Aug 14 2021
parent Marcone <marcone email.com> writes:
On Saturday, 14 August 2021 at 08:24:41 UTC, user1234 wrote:
 On Friday, 13 August 2021 at 23:33:05 UTC, Paul Backus wrote:
 On Friday, 13 August 2021 at 23:23:55 UTC, Marcone wrote:
 writeln("Hello World!"[x.indexOf("e")..x.indexOf("r")]);

 indexOf()is just a simple example, not the goal. I want 
 handle literal inside [] like it bellow, but in literal:

 string x = "Hello World!";
 writeln(x[x.indexOf("e")..x.indexOf("r")]);
You can use the `pipe` function to bind an arbitrary expression to a variable: ```d import std.functional: pipe; import std.algorithm: countUntil; import std.stdio: writeln; "Hello world!" .pipe!(s => s[s.countUntil('e') .. s.countUntil('r')]) .writeln; ```
nice, that's the best alternative.
Very Good!!! This pipe!() is just what I am looking for. Thank you very much!!!!
Aug 14 2021
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/13/21 4:23 PM, Marcone wrote:

 string x = "Hello World!";
 writeln(x[x.indexOf("e")..x.indexOf("r")]);
I don't see the usefulness and there are the following problems with it: - Not an algorithmic complexity issue but it sounds to me like a pessimization to go through the elements in linear fashion, obtain indexes and then iterate between the indexes again. - This approach requires random access, which only a subset of collections provide. - The semantics of the second index is not clear. What is the intent when we say "from 'f' to 'n'" in the string "confusing"? Is it an error because the indexes 3..2 would be illegal? Or did we mean second 'n' in the string? On the other hand, the programmer can build any semantic with the existing range algorithms. And that would work even with InputRanges. You didn't ask but sorry, this feature is not for me. :) Ali
Aug 13 2021
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Aug 13, 2021 at 04:35:54PM -0700, Ali Çehreli via Digitalmars-d-learn
wrote:
 On 8/13/21 4:23 PM, Marcone wrote:
 
 string x = "Hello World!";
 writeln(x[x.indexOf("e")..x.indexOf("r")]);
I don't see the usefulness and there are the following problems with it: - Not an algorithmic complexity issue but it sounds to me like a pessimization to go through the elements in linear fashion, obtain indexes and then iterate between the indexes again.
[...] In the above example, what all those indexOf calls really want to say is, "give me a slice of x starting from the first occurrence of 'e' to the next occurrence of 'r'". Once this is understood, the rest follows: writeln(x.find('e') // find first occurrence of 'e' .until('r') // slice until next occurrence of 'r' ); Or more concisely: writeln(x.find('e').until('r')); This iterates x only once, and also avoids the pathological case where 'r' appears before 'e', which in the original code would throw a RangeError because it generates a slice of negative length. // OTOH, if the OP insists that he wants arbitrary expressions inside [...], one way to do it is to overload opSlice and opIndex, then create placeholder objects that abstractly refer to parts of a string that opIndex then interprets. Something like this: // Warning: untested code struct Idx { dchar ch; } struct SliceRange { size_t start, end; } struct StringWrapper { string impl; alias impl this; SliceRange opSlice(Idx i1, Idx i2) { return SliceRange(impl.indexOf(i1.ch), impl.indexOf(i2.ch)); // or whatever more efficient implementation you // wish to use } auto opIndex(SliceRange sr) { return StringWrapper(impl[sr.start, sr.end]); } // Don't forget to implement .opDollar, which I omit // here for conciseness. } StringWrapper blah = "abcdefgh"; assert(blah[Idx('c') .. Idx('g')] == "cdefg"); Note that the above is incomplete; it's just a sketch of the concept. To make it work for all cases, opSlice needs to handle if one or both of the indices are integers, etc.. And Idx probably needs operator overloading in order to support arbitrary expressions (it basically amounts to an expression template or a runtime expression tree, if taken to its logical conclusion). Truth be told, though, this is killing an ant with a nuclear warhead. Why not just write `x.find('e').until('r')` instead. ;-) T -- Valentine's Day: an occasion for florists to reach into the wallets of nominal lovers in dire need of being reminded to profess their hypothetical love for their long-forgotten.
Aug 13 2021
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/13/21 7:23 PM, Marcone wrote:
 On Friday, 13 August 2021 at 23:08:07 UTC, jfondren wrote:
 On Friday, 13 August 2021 at 22:09:59 UTC, Marcone wrote:
 Isn't there some unario operator template that I can use with lambda 
 to handle a string literal?
So, something other than an exact "lit"[0..this.xx(..)] syntax is fine? What didn't you like about `"Hello World!".findSplit("o")[0].writeln;` then? What is a real example of something you want to do?
writeln("Hello World!"[x.indexOf("e")..x.indexOf("r")]); indexOf()is just a simple example, not the goal. I want handle literal inside [] like it bellow, but in literal: string x = "Hello World!"; writeln(x[x.indexOf("e")..x.indexOf("r")]);
Operator overloading is only available to custom types (structs or classes), and not to arrays. You can create a type to do what you want. e.g.: ```d struct SliceByIndexOf { string s; auto opIndex(size_t[2] idxs) { return SliceByIndexOf(s[ idxs[0] .. idxs[1]]); } size_t[2] opSlice(size_t dim : 0)(string s1, string s2) { import std.string; return [s.indexOf(s1), s.indexOf(s2)]; } string toString() { return s; } } auto sbio(string s) { return SliceByIndexOf(s); } void main() { import std.stdio; writeln("Hello World!".sbio["e" .. "r"]); // "ello Wo" } ``` -Steve
Aug 13 2021