How to extend the string class to return this inside the square bracket?

H. S. Teoh hsteoh at quickfur.ath.cx
Sat Aug 14 00:27:02 UTC 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.


More information about the Digitalmars-d-learn mailing list