Search code examples
c#exceptionindexofcurrentculture

ArgumentOutOfRangeException using IndexOf with CultureInfo 1031


string s = "Gewerbegebiet Waldstraße"; //other possible input "Waldstrasse"

int iFoundStart = s.IndexOf("strasse", StringComparison.CurrentCulture);
if (iFoundStart > -1)
    s = s.Remove(iFoundStart, 7);

I'm running CultureInfo 1031 (german).

IndexOf matches 'straße' or 'strasse' with defined 'strasse' and returns 18 as position.

Neither Remove nor Replace got any overload for setting a culture.

If I remove 6 chars using Remove 1 character will be left if input-string is 'strasse' and 'straße' will work. If input-string is 'straße' and I remove 7 chars I get ArgumentOutOfRangeException.

Is there a way to safely remove the found string? Any method which provides the last index of IndexOf? I stepped closer into IndexOf and it's native code under the hood as expected - so no way to do something own...


Solution

  • The native Win32 API does expose the length of the string that was found. You can use P/Invoke to call FindNLSStringEx directly:

    static class CompareInfoExtensions
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
        private static extern int FindNLSStringEx(string lpLocaleName, uint dwFindNLSStringFlags, string lpStringSource, int cchSource, string lpStringValue, int cchValue, out int pcchFound, IntPtr lpVersionInformation, IntPtr lpReserved, int sortHandle);
    
        const uint FIND_FROMSTART = 0x00400000;
    
        public static int IndexOfEx(this CompareInfo compareInfo, string source, string value, int startIndex, int count, CompareOptions options, out int length)
        {
            // Argument validation omitted for brevity
            return FindNLSStringEx(compareInfo.Name, FIND_FROMSTART, source, source.Length, value, value.Length, out length, IntPtr.Zero, IntPtr.Zero, 0);
        }
    }
    
    static class Program
    {
        static void Main()
        {
            var s = "<<Gewerbegebiet Waldstraße>>";
            //var s = "<<Gewerbegebiet Waldstrasse>>";
            int length;
            int start = new CultureInfo("de-DE").CompareInfo.IndexOfEx(s, "strasse", 0, s.Length, CompareOptions.None, out length);
            Console.WriteLine(s.Substring(0, start) + s.Substring(start + length));
        }
    }
    

    I'm not seeing a way to do this using purely the BCL.