【问题标题】:ArgumentOutOfRangeException using IndexOf with CultureInfo 1031ArgumentOutOfRangeException 使用 IndexOf 和 CultureInfo 1031
【发布时间】:2015-11-05 18:15:21
【问题描述】:
string s = "Gewerbegebiet Waldstraße"; //other possible input "Waldstrasse"

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

我正在运行 CultureInfo 1031(德语)。

IndexOf 将 'straße' 或 'strasse' 与定义的 'strasse' 匹配,并返回 18 作为位置。

Remove 和 Replace 都没有为设置文化带来任何负担。

如果我使用删除 1 个字符删除 6 个字符,如果输入字符串为“strasse”并且“straße”将起作用。 如果输入字符串是“straße”并且我删除了 7 个字符,我会得到 ArgumentOutOfRangeException。

有没有办法安全地删除找到的字符串?有什么方法可以提供 IndexOf 的最后一个索引?我更接近 IndexOf 并且它是引擎盖下的本机代码 - 所以没有办法自己做一些事情......

【问题讨论】:

  • 用空字符串替换它怎么样? s = s.Replace("strasse","");
  • @dotctor 我相信 OP 说string.Replace 没有考虑文化,所以“ss”不匹配“ß”。
  • 我在 en-US 上运行并遇到了这个问题。问题是 IndexOf 的行为不同。
  • @M.kazemAkhgary 因为英文中的“ß”和“ss”不一样。
  • 如果你先做s.Replace("ß", "ss");会怎么样?

标签: c# exception indexof currentculture


【解决方案1】:

本机 Win32 API 确实公开了找到的字符串的长度。您可以使用 P/Invoke 直接调用FindNLSStringEx

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));
    }
}

我没有看到纯粹使用 BCL 的方法。

【讨论】:

  • 如果我想匹配 'Berliner Straße' 并使用 CompareOptions.IgnoreCase 失败 - 知道为什么吗?
  • @isHuman 我省略了从CompareOptionsFindNLSStringEx 选项值的转换:您可以看到options 参数没有被使用。您需要添加从CompareOptions.IgnoreCaseLINGUISTIC_IGNORECASENORM_IGNORECASE 的转换(由您决定)。
  • 这似乎有效。我定义了另一个标志LINGUISTIC_IGNORECASE 并使用| 将它与FIND_FROMSTART 结合起来。谢谢,太糟糕了,没有高级方法可以做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多