August 13, 2021
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

August 13, 2021
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.


August 13, 2021

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.:

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

August 13, 2021
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.
August 14, 2021

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:

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.

August 14, 2021

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:

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!!!!

1 2
Next ›   Last »