// Written in the D programming language. /**String handling functions. $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex,$(BOOKTABLE ,$(TR $(TH Category) $(TH Functions) )$(TR $(TDNW Searching) $(TD $(MYREF column) $(MYREF indexOf) $(MYREF indexOfAny) $(MYREF indexOfNeither) $(MYREF lastIndexOf) $(MYREF lastIndexOfAny) $(MYREF lastIndexOfNeither) ))$(TR $(TDNW Comparison) $(TD $(MYREF isNumeric) ))$(TR $(TDNW Mutation) $(TD $(MYREF capitalize) ))$(TR $(TDNW Pruning and Filling) $(TD $(MYREF center) $(MYREF chomp) $(MYREF chompPrefix) $(MYREF chop) $(MYREF detabber) $(MYREF detab) $(MYREF entab) $(MYREF entabber) $(MYREF leftJustify) $(MYREF outdent) $(MYREF rightJustify) $(MYREF strip) $(MYREF stripLeft) $(MYREF stripRight) $(MYREF wrap) ))$(TR $(TDNW Substitution) $(TD $(MYREF abbrev) $(MYREF soundex) $(MYREF soundexer) $(MYREF succ) $(MYREF tr) $(MYREF translate) ))$(TR $(TDNW Miscellaneous) $(TD $(MYREF assumeUTF) $(MYREF fromStringz) $(MYREF lineSplitter) $(MYREF representation) $(MYREF splitLines) $(MYREF toStringz) )))) Objects of types `string`, `wstring`, and `dstring` are value typesand cannot be mutated element-by-element. For using mutation during buildingstrings, use `char[]`, `wchar[]`, or `dchar[]`. The `xxxstring`types are preferable because they don't exhibit undesired aliasing, thusmaking code more robust. The following functions are publicly imported: $(BOOKTABLE ,$(TR $(TH Module) $(TH Functions) )$(LEADINGROW Publicly imported functions) $(TR $(TD std.algorithm) $(TD $(REF_SHORT cmp, std,algorithm,comparison) $(REF_SHORT count, std,algorithm,searching) $(REF_SHORT endsWith, std,algorithm,searching) $(REF_SHORT startsWith, std,algorithm,searching) )) $(TR $(TD std.array) $(TD $(REF_SHORT join, std,array) $(REF_SHORT replace, std,array) $(REF_SHORT replaceInPlace, std,array) $(REF_SHORT split, std,array) $(REF_SHORT empty, std,array) )) $(TR $(TD std.format) $(TD $(REF_SHORT format, std,format) $(REF_SHORT sformat, std,format) )) $(TR $(TD std.uni) $(TD $(REF_SHORT icmp, std,uni) $(REF_SHORT toLower, std,uni) $(REF_SHORT toLowerInPlace, std,uni) $(REF_SHORT toUpper, std,uni) $(REF_SHORT toUpperInPlace, std,uni) ))) There is a rich set of functions for string handling defined in other modules.Functions related to Unicode and ASCII are found in $(MREF std, uni)and $(MREF std, ascii), respectively. Other functions that have awider generality than just strings can be found in $(MREF std, algorithm)and $(MREF std, range). See_Also: $(LIST $(MREF std, algorithm) and $(MREF std, range) for generic range algorithms , $(MREF std, ascii) for functions that work with ASCII strings , $(MREF std, uni) for functions that work with unicode strings ) Copyright: Copyright The D Language Foundation 2007-. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP digitalmars.com, Walter Bright), $(HTTP erdani.org, Andrei Alexandrescu), $(HTTP jmdavisprog.com, Jonathan M Davis), and David L. 'SpottedTiger' Davis Source: $(PHOBOSSRC std/string.d) */module std.string; version (StdUnittest){private: struct TestAliasedString { string get() @safe @nogc pure nothrow return scope { return _s; } alias get this; @disable this(this); string _s; } bool testAliasedString(alias func, Args...)(string s, Args args) { import std.algorithm.comparison : equal; auto a = func(TestAliasedString(s), args); auto b = func(s, args); static if (is(typeof(equal(a, b)))) { // For ranges, compare contents instead of object identity. return equal(a, b); } else { return a == b; } }} public import std.format : format, sformat;import std.typecons : Flag, Yes, No;public import std.uni : icmp, toLower, toLowerInPlace, toUpper, toUpperInPlace; import std.meta : AliasSeq, staticIndexOf;import std.range.primitives : back, ElementEncodingType, ElementType, front, hasLength, hasSlicing, isBidirectionalRange, isForwardRange, isInfinite, isInputRange, isOutputRange, isRandomAccessRange, popBack, popFront, put, save;import std.traits : isConvertibleToString, isNarrowString, isSomeChar, isSomeString, StringTypeOf, Unqual; //public imports for backward compatibilitypublic import std.algorithm.comparison : cmp;public import std.algorithm.searching : startsWith, endsWith, count;public import std.array : join, replace, replaceInPlace, split, empty; /* ************* Exceptions *************** */ /++ Exception thrown on errors in std.string functions. +/class StringException : Exception{ import std.exception : basicExceptionCtors; /// mixin basicExceptionCtors;} ///@safe pure unittest{ import std.exception : assertThrown; auto bad = " a\n\tb\n c"; assertThrown!StringException(bad.outdent);} /++ Params: cString = A null-terminated c-style string. Returns: A D-style array of `char`, `wchar` or `dchar` referencing the same string. The returned array will retain the same type qualifiers as the input. $(RED Important Note:) The returned array is a slice of the original buffer. The original data is not changed and not copied.+/inout(Char)[] fromStringz(Char)(return scope inout(Char)* cString) @nogc @system pure nothrowif (isSomeChar!Char){ import core.stdc.stddef : wchar_t; static if (is(immutable Char == immutable char)) import core.stdc.string : cstrlen = strlen; else static if (is(immutable Char == immutable wchar_t)) import core.stdc.wchar_ : cstrlen = wcslen; else static size_t cstrlen(scope const Char* s) { const(Char)* p = s; while (*p) ++p; return p - s; } return cString ? cString[0 .. cstrlen(cString)] : null;} /// dittoinout(Char)[] fromStringz(Char)(return scope inout(Char)[] cString) @nogc @safe pure nothrowif (isSomeChar!Char){ foreach (i; 0 .. cString.length) if (cString[i] == '\0') return cString[0 .. i]; return cString;} ///@system pure unittest{ assert(fromStringz("foo\0"c.ptr) == "foo"c); assert(fromStringz("foo\0"w.ptr) == "foo"w); assert(fromStringz("foo\0"d.ptr) == "foo"d); assert(fromStringz("福\0"c.ptr) == "福"c); assert(fromStringz("福\0"w.ptr) == "福"w); assert(fromStringz("福\0"d.ptr) == "福"d);} ///@nogc @safe pure nothrow unittest{ struct C { char[32] name; } assert(C("foo\0"c).name.fromStringz() == "foo"c); struct W { wchar[32] name; } assert(W("foo\0"w).name.fromStringz() == "foo"w); struct D { dchar[32] name; } assert(D("foo\0"d).name.fromStringz() == "foo"d);} @nogc @safe pure nothrow unittest{ assert( string.init.fromStringz() == ""c); assert(wstring.init.fromStringz() == ""w); assert(dstring.init.fromStringz() == ""d); immutable char[3] a = "foo"c; assert(a.fromStringz() == "foo"c); immutable wchar[3] b = "foo"w; assert(b.fromStringz() == "foo"w); immutable dchar[3] c = "foo"d; assert(c.fromStringz() == "foo"d);} @system pure unittest{ char* a = null; assert(fromStringz(a) == null); wchar* b = null; assert(fromStringz(b) == null); dchar* c = null; assert(fromStringz(c) == null); const char* d = "foo\0"; assert(fromStringz(d) == "foo"); immutable char* e = "foo\0"; assert(fromStringz(e) == "foo"); const wchar* f = "foo\0"; assert(fromStringz(f) == "foo"); immutable wchar* g = "foo\0"; assert(fromStringz(g) == "foo"); const dchar* h = "foo\0"; assert(fromStringz(h) == "foo"); immutable dchar* i = "foo\0"; assert(fromStringz(i) == "foo"); immutable wchar z = 0x0000; // Test some surrogate pairs // high surrogates are in the range 0xD800 .. 0xDC00 // low surrogates are in the range 0xDC00 .. 0xE000 // since UTF16 doesn't specify endianness we test both. foreach (wchar[] t; [[0xD800, 0xDC00], [0xD800, 0xE000], [0xDC00, 0xDC00], [0xDC00, 0xE000], [0xDA00, 0xDE00]]) { immutable hi = t[0], lo = t[1]; assert(fromStringz([hi, lo, z].ptr) == [hi, lo]); assert(fromStringz([lo, hi, z].ptr) == [lo, hi]); }} /++ Params: s = A D-style string. Returns: A C-style null-terminated string equivalent to `s`. `s` must not contain embedded `'\0'`'s as any C function will treat the first `'\0'` that it sees as the end of the string. If `s.empty` is `true`, then a string containing only `'\0'` is returned. $(RED Important Note:) When passing a `char*` to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it. +/immutable(char)* toStringz(scope const(char)[] s) @trusted pure nothrowout (result){ import core.stdc.string : strlen, memcmp; if (result) { auto slen = s.length; while (slen > 0 && s[slen-1] == 0) --slen; assert(strlen(result) == slen, "The result c string is shorter than the in input string"); assert(result[0 .. slen] == s[0 .. slen], "The input and result string are not equal"); }}do{ import std.exception : assumeUnique; if (s.empty) return "".ptr; /+ Unfortunately, this isn't reliable. We could make this work if string literals are put in read-only memory and we test if s[] is pointing into that. /* Peek past end of s[], if it's 0, no conversion necessary. * Note that the compiler will put a 0 past the end of static * strings, and the storage allocator will put a 0 past the end * of newly allocated char[]'s. */ char* p = &s[0] + s.length; if (*p == 0) return s; +/ // Need to make a copy auto copy = new char[s.length + 1]; copy[0 .. s.length] = s[]; copy[s.length] = 0; return &assumeUnique(copy)[0];} ///pure nothrow @system unittest{ import core.stdc.string : strlen; import std.conv : to; auto p = toStringz("foo"); assert(strlen(p) == 3); const(char)[] foo = "abbzxyzzy"; p = toStringz(foo[3 .. 5]); assert(strlen(p) == 2); string test = ""; p = toStringz(test); assert(*p == 0); test = "\0"; p = toStringz(test); assert(*p == 0); test = "foo\0"; p = toStringz(test); assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0); const string test2 = ""; p = toStringz(test2); assert(*p == 0); assert(toStringz([]) is toStringz(""));} pure nothrow @system unittest // https://issues.dlang.org/show_bug.cgi?id=15136{ static struct S { immutable char[5] str; ubyte foo; this(char[5] str) pure nothrow { this.str = str; } } auto s = S("01234"); const str = s.str.toStringz; assert(str !is s.str.ptr); assert(*(str + 5) == 0); // Null terminated. s.foo = 42; assert(*(str + 5) == 0); // Still null terminated.} /** Flag indicating whether a search is case-sensitive.*/alias CaseSensitive = Flag!"caseSensitive"; /++ Searches for a character in a string or range. Params: s = string or InputRange of characters to search for `c` in c = character to search for in `s` startIdx = index to a well-formed code point in `s` to start searching from; defaults to 0 cs = specifies whether comparisons are case-sensitive (`Yes.caseSensitive`) or not (`No.caseSensitive`). Returns: If `c` is found in `s`, then the index of its first occurrence is returned. If `c` is not found or `startIdx` is greater than or equal to `s.length`, then -1 is returned. If the parameters are not valid UTF, the result will still be either -1 or in the range [`startIdx` .. `s.length`], but will not be reliable otherwise. Throws: If the sequence starting at `startIdx` does not represent a well-formed code point, then a $(REF UTFException, std,utf) may be thrown. See_Also: $(REF countUntil, std,algorithm,searching) +/ptrdiff_t indexOf(Range)(Range s, dchar c, CaseSensitive cs = Yes.caseSensitive)if (isInputRange!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range){ return _indexOf(s, c, cs);} /// Dittoptrdiff_t indexOf(C)(scope const(C)[] s, dchar c, CaseSensitive cs = Yes.caseSensitive)if (isSomeChar!C){ return _indexOf(s, c, cs);} /// Dittoptrdiff_t indexOf(Range)(Range s, dchar c, size_t startIdx, CaseSensitive cs = Yes.caseSensitive)if (isInputRange!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range){ return _indexOf(s, c, startIdx, cs);Lines 1–500 of 7323. Load more
// Written in the D programming language. /** String handling functions. $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW Searching) $(TD $(MYREF column) $(MYREF indexOf) $(MYREF indexOfAny) $(MYREF indexOfNeither) $(MYREF lastIndexOf) $(MYREF lastIndexOfAny) $(MYREF lastIndexOfNeither) ) ) $(TR $(TDNW Comparison) $(TD $(MYREF isNumeric) ) ) $(TR $(TDNW Mutation) $(TD $(MYREF capitalize) ) ) $(TR $(TDNW Pruning and Filling) $(TD $(MYREF center) $(MYREF chomp) $(MYREF chompPrefix) $(MYREF chop) $(MYREF detabber) $(MYREF detab) $(MYREF entab) $(MYREF entabber) $(MYREF leftJustify) $(MYREF outdent) $(MYREF rightJustify) $(MYREF strip) $(MYREF stripLeft) $(MYREF stripRight) $(MYREF wrap) ) ) $(TR $(TDNW Substitution) $(TD $(MYREF abbrev) $(MYREF soundex) $(MYREF soundexer) $(MYREF succ) $(MYREF tr) $(MYREF translate) ) ) $(TR $(TDNW Miscellaneous) $(TD $(MYREF assumeUTF) $(MYREF fromStringz) $(MYREF lineSplitter) $(MYREF representation) $(MYREF splitLines) $(MYREF toStringz) ) ))) Objects of types `string`, `wstring`, and `dstring` are value types and cannot be mutated element-by-element. For using mutation during building strings, use `char[]`, `wchar[]`, or `dchar[]`. The `xxxstring` types are preferable because they don't exhibit undesired aliasing, thus making code more robust. The following functions are publicly imported: $(BOOKTABLE , $(TR $(TH Module) $(TH Functions) ) $(LEADINGROW Publicly imported functions) $(TR $(TD std.algorithm) $(TD $(REF_SHORT cmp, std,algorithm,comparison) $(REF_SHORT count, std,algorithm,searching) $(REF_SHORT endsWith, std,algorithm,searching) $(REF_SHORT startsWith, std,algorithm,searching) )) $(TR $(TD std.array) $(TD $(REF_SHORT join, std,array) $(REF_SHORT replace, std,array) $(REF_SHORT replaceInPlace, std,array) $(REF_SHORT split, std,array) $(REF_SHORT empty, std,array) )) $(TR $(TD std.format) $(TD $(REF_SHORT format, std,format) $(REF_SHORT sformat, std,format) )) $(TR $(TD std.uni) $(TD $(REF_SHORT icmp, std,uni) $(REF_SHORT toLower, std,uni) $(REF_SHORT toLowerInPlace, std,uni) $(REF_SHORT toUpper, std,uni) $(REF_SHORT toUpperInPlace, std,uni) )) ) There is a rich set of functions for string handling defined in other modules. Functions related to Unicode and ASCII are found in $(MREF std, uni) and $(MREF std, ascii), respectively. Other functions that have a wider generality than just strings can be found in $(MREF std, algorithm) and $(MREF std, range). See_Also: $(LIST $(MREF std, algorithm) and $(MREF std, range) for generic range algorithms , $(MREF std, ascii) for functions that work with ASCII strings , $(MREF std, uni) for functions that work with unicode strings ) Copyright: Copyright The D Language Foundation 2007-. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP digitalmars.com, Walter Bright), $(HTTP erdani.org, Andrei Alexandrescu), $(HTTP jmdavisprog.com, Jonathan M Davis), and David L. 'SpottedTiger' Davis Source: $(PHOBOSSRC std/string.d) */ module std.string; version (StdUnittest) { private: struct TestAliasedString { string get() @safe @nogc pure nothrow return scope { return _s; } alias get this; @disable this(this); string _s; } bool testAliasedString(alias func, Args...)(string s, Args args) { import std.algorithm.comparison : equal; auto a = func(TestAliasedString(s), args); auto b = func(s, args); static if (is(typeof(equal(a, b)))) { // For ranges, compare contents instead of object identity. return equal(a, b); } else { return a == b; } } } public import std.format : format, sformat; import std.typecons : Flag, Yes, No; public import std.uni : icmp, toLower, toLowerInPlace, toUpper, toUpperInPlace; import std.meta : AliasSeq, staticIndexOf; import std.range.primitives : back, ElementEncodingType, ElementType, front, hasLength, hasSlicing, isBidirectionalRange, isForwardRange, isInfinite, isInputRange, isOutputRange, isRandomAccessRange, popBack, popFront, put, save; import std.traits : isConvertibleToString, isNarrowString, isSomeChar, isSomeString, StringTypeOf, Unqual; //public imports for backward compatibility public import std.algorithm.comparison : cmp; public import std.algorithm.searching : startsWith, endsWith, count; public import std.array : join, replace, replaceInPlace, split, empty; /* ************* Exceptions *************** */ /++ Exception thrown on errors in std.string functions. +/ class StringException : Exception { import std.exception : basicExceptionCtors; /// mixin basicExceptionCtors; } /// @safe pure unittest { import std.exception : assertThrown; auto bad = " a\n\tb\n c"; assertThrown!StringException(bad.outdent); } /++ Params: cString = A null-terminated c-style string. Returns: A D-style array of `char`, `wchar` or `dchar` referencing the same string. The returned array will retain the same type qualifiers as the input. $(RED Important Note:) The returned array is a slice of the original buffer. The original data is not changed and not copied. +/ inout(Char)[] fromStringz(Char)(return scope inout(Char)* cString) @nogc @system pure nothrow if (isSomeChar!Char) { import core.stdc.stddef : wchar_t; static if (is(immutable Char == immutable char)) import core.stdc.string : cstrlen = strlen; else static if (is(immutable Char == immutable wchar_t)) import core.stdc.wchar_ : cstrlen = wcslen; else static size_t cstrlen(scope const Char* s) { const(Char)* p = s; while (*p) ++p; return p - s; } return cString ? cString[0 .. cstrlen(cString)] : null; } /// ditto inout(Char)[] fromStringz(Char)(return scope inout(Char)[] cString) @nogc @safe pure nothrow if (isSomeChar!Char) { foreach (i; 0 .. cString.length) if (cString[i] == '\0') return cString[0 .. i]; return cString; } /// @system pure unittest { assert(fromStringz("foo\0"c.ptr) == "foo"c); assert(fromStringz("foo\0"w.ptr) == "foo"w); assert(fromStringz("foo\0"d.ptr) == "foo"d); assert(fromStringz("福\0"c.ptr) == "福"c); assert(fromStringz("福\0"w.ptr) == "福"w); assert(fromStringz("福\0"d.ptr) == "福"d); } /// @nogc @safe pure nothrow unittest { struct C { char[32] name; } assert(C("foo\0"c).name.fromStringz() == "foo"c); struct W { wchar[32] name; } assert(W("foo\0"w).name.fromStringz() == "foo"w); struct D { dchar[32] name; } assert(D("foo\0"d).name.fromStringz() == "foo"d); } @nogc @safe pure nothrow unittest { assert( string.init.fromStringz() == ""c); assert(wstring.init.fromStringz() == ""w); assert(dstring.init.fromStringz() == ""d); immutable char[3] a = "foo"c; assert(a.fromStringz() == "foo"c); immutable wchar[3] b = "foo"w; assert(b.fromStringz() == "foo"w); immutable dchar[3] c = "foo"d; assert(c.fromStringz() == "foo"d); } @system pure unittest { char* a = null; assert(fromStringz(a) == null); wchar* b = null; assert(fromStringz(b) == null); dchar* c = null; assert(fromStringz(c) == null); const char* d = "foo\0"; assert(fromStringz(d) == "foo"); immutable char* e = "foo\0"; assert(fromStringz(e) == "foo"); const wchar* f = "foo\0"; assert(fromStringz(f) == "foo"); immutable wchar* g = "foo\0"; assert(fromStringz(g) == "foo"); const dchar* h = "foo\0"; assert(fromStringz(h) == "foo"); immutable dchar* i = "foo\0"; assert(fromStringz(i) == "foo"); immutable wchar z = 0x0000; // Test some surrogate pairs // high surrogates are in the range 0xD800 .. 0xDC00 // low surrogates are in the range 0xDC00 .. 0xE000 // since UTF16 doesn't specify endianness we test both. foreach (wchar[] t; [[0xD800, 0xDC00], [0xD800, 0xE000], [0xDC00, 0xDC00], [0xDC00, 0xE000], [0xDA00, 0xDE00]]) { immutable hi = t[0], lo = t[1]; assert(fromStringz([hi, lo, z].ptr) == [hi, lo]); assert(fromStringz([lo, hi, z].ptr) == [lo, hi]); } } /++ Params: s = A D-style string. Returns: A C-style null-terminated string equivalent to `s`. `s` must not contain embedded `'\0'`'s as any C function will treat the first `'\0'` that it sees as the end of the string. If `s.empty` is `true`, then a string containing only `'\0'` is returned. $(RED Important Note:) When passing a `char*` to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it. +/ immutable(char)* toStringz(scope const(char)[] s) @trusted pure nothrow out (result) { import core.stdc.string : strlen, memcmp; if (result) { auto slen = s.length; while (slen > 0 && s[slen-1] == 0) --slen; assert(strlen(result) == slen, "The result c string is shorter than the in input string"); assert(result[0 .. slen] == s[0 .. slen], "The input and result string are not equal"); } } do { import std.exception : assumeUnique; if (s.empty) return "".ptr; /+ Unfortunately, this isn't reliable. We could make this work if string literals are put in read-only memory and we test if s[] is pointing into that. /* Peek past end of s[], if it's 0, no conversion necessary. * Note that the compiler will put a 0 past the end of static * strings, and the storage allocator will put a 0 past the end * of newly allocated char[]'s. */ char* p = &s[0] + s.length; if (*p == 0) return s; +/ // Need to make a copy auto copy = new char[s.length + 1]; copy[0 .. s.length] = s[]; copy[s.length] = 0; return &assumeUnique(copy)[0]; } /// pure nothrow @system unittest { import core.stdc.string : strlen; import std.conv : to; auto p = toStringz("foo"); assert(strlen(p) == 3); const(char)[] foo = "abbzxyzzy"; p = toStringz(foo[3 .. 5]); assert(strlen(p) == 2); string test = ""; p = toStringz(test); assert(*p == 0); test = "\0"; p = toStringz(test); assert(*p == 0); test = "foo\0"; p = toStringz(test); assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0); const string test2 = ""; p = toStringz(test2); assert(*p == 0); assert(toStringz([]) is toStringz("")); } pure nothrow @system unittest // https://issues.dlang.org/show_bug.cgi?id=15136 { static struct S { immutable char[5] str; ubyte foo; this(char[5] str) pure nothrow { this.str = str; } } auto s = S("01234"); const str = s.str.toStringz; assert(str !is s.str.ptr); assert(*(str + 5) == 0); // Null terminated. s.foo = 42; assert(*(str + 5) == 0); // Still null terminated. } /** Flag indicating whether a search is case-sensitive. */ alias CaseSensitive = Flag!"caseSensitive"; /++ Searches for a character in a string or range. Params: s = string or InputRange of characters to search for `c` in c = character to search for in `s` startIdx = index to a well-formed code point in `s` to start searching from; defaults to 0 cs = specifies whether comparisons are case-sensitive (`Yes.caseSensitive`) or not (`No.caseSensitive`). Returns: If `c` is found in `s`, then the index of its first occurrence is returned. If `c` is not found or `startIdx` is greater than or equal to `s.length`, then -1 is returned. If the parameters are not valid UTF, the result will still be either -1 or in the range [`startIdx` .. `s.length`], but will not be reliable otherwise. Throws: If the sequence starting at `startIdx` does not represent a well-formed code point, then a $(REF UTFException, std,utf) may be thrown. See_Also: $(REF countUntil, std,algorithm,searching) +/ ptrdiff_t indexOf(Range)(Range s, dchar c, CaseSensitive cs = Yes.caseSensitive) if (isInputRange!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range) { return _indexOf(s, c, cs); } /// Ditto ptrdiff_t indexOf(C)(scope const(C)[] s, dchar c, CaseSensitive cs = Yes.caseSensitive) if (isSomeChar!C) { return _indexOf(s, c, cs); } /// Ditto ptrdiff_t indexOf(Range)(Range s, dchar c, size_t startIdx, CaseSensitive cs = Yes.caseSensitive) if (isInputRange!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range) { return _indexOf(s, c, startIdx, cs);