【问题标题】:Filter a String过滤字符串
【发布时间】:2010-10-28 19:46:22
【问题描述】:

我想确保一个字符串只有这个范围内的字符

[a-z] && [A-Z] && [0-9] && [-]

所以所有字母和数字加上连字符。 我试过这个...

C# 应用程序:

        char[] filteredChars = { ',', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '{', '}', '[', ']', ':', ';', '"', '\'', '?', '/', '.', '<', '>', '\\', '|' };
        string s = str.TrimStart(filteredChars);

这个 TrimStart() 似乎只适用于字母,没有 $ % 等其他字符

我是不是执行错了? 有更好的方法吗?

我只是想避免循环遍历每个字符串的索引检查,因为会有很多字符串要做...

想法?

谢谢!

【问题讨论】:

  • 您应该检查输入是否有效,而不是不应该输入的内容。使用正则表达式检查您的字符串。

标签: c# string filtering


【解决方案1】:

我已经在 Linqpad 5 中测试了这两种解决方案。它们的好处是它们不仅可以用于整数,还可以用于带有数字小数分隔符的小数/浮点数,这取决于文化。例如,在挪威,我们使用逗号作为小数分隔符,而在美国,使用点。逗号在那里用作千位分隔符。无论如何,首先是 Linq 版本,然后是 Regex 版本。最简洁的一点是访问 Thread 的数字分隔符的静态属性,但您可以使用代码顶部的 static 对其进行压缩,或者更好 - 将此类功能放入 C# 扩展方法中,最好使用任意正则表达式模式进行重载。

string crappyNumber = @"40430dfkZZZdfldslkggh430FDFLDEFllll340-DIALNOWFORCHRISTSAKE.,CAKE-FORFIRSTDIAL920932903209032093294faøj##R#KKL##K";

string.Join("", crappyNumber.Where(c => char.IsDigit(c)|| c.ToString() == Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator)).Dump();

new String(crappyNumber.Where(c => new Regex($"[\\d]+{Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator}\\d+").IsMatch(c.ToString())).ToArray()).Dump();

请注意上面的代码,Dump() 方法将结果转储到 Linqpad。您的代码当然会跳过最后一部分。另请注意,我们将其归结为单行,但它仍然有点冗长,可以按照建议放入 C# 扩展方法中。

另外,与 string.join 不同,newing 一个新的 String 对象语法更紧凑,更不容易出错。

我们得到了一个糟糕的数字作为输入,但我们最终还是设法得到了我们的数字!它在 C# 中具有文化意识!

【讨论】:

    【解决方案2】:

    这是一种使用 LINQ 的有趣方法 - 没有丑陋的循环,没有复杂的 RegEx:

    private string GetGoodString(string input)
    {
       var allowedChars = 
          Enumerable.Range('0', 10).Concat(
          Enumerable.Range('A', 26)).Concat(
          Enumerable.Range('a', 26)).Concat(
          Enumerable.Range('-', 1));
    
       var goodChars = input.Where(c => allowedChars.Contains(c));
       return new string(goodChars.ToArray());
    }
    

    喂它“你好,世界?123!”它会返回“Helloworld123”。

    【讨论】:

    • 我必须说我喜欢这个,只是因为你避免使用 RegExes =) +1!
    【解决方案3】:

    这似乎是使用regular expression 的完全正当理由。

    bool stringIsValid = Regex.IsMatch(inputString, @"^[a-zA-Z0-9\-]*?$");
    

    针对 miguel 的评论,您可以这样做以删除所有不需要的字符:

    string cleanString = Regex.Replace(inputString, @"[^a-zA-Z0-9\-]", "");
    

    请注意,插入符号 (^) 现在被放置在内部字符类中,因此否定它(匹配任何不允许的字符)。

    【讨论】:

    • 一点免责声明:我只是从头顶开始制作图案,所以它可能不是你想要的。如果您点击链接,您将能够找到构建理想模式所需的信息。
    • 你需要在字符串前面放一个@符号,这样它就不会试图转义 - : Regex.Replace(s, @"[^A-z0-9\-]", "");
    • 太棒了,正是我想要的!
    • 什么是?在表达式中做什么??
    • 引用来自正则表达式.info/reference.html: ? “使前面的项目成为可选的。贪婪,所以如果可能的话,可选项目包含在匹配中。”现在我想起来了,你可能不希望在这个特定的模式中这样做,但我认为不管有没有……
    【解决方案4】:

    试试下面的

    public bool isStringValid(string input) {
      if ( null == input ) { 
        throw new ArgumentNullException("input");
      }
      return System.Text.RegularExpressions.Regex.IsMatch(input, "^[A-Za-z0-9\-]*$");
    }
    

    【讨论】:

    • 或者你可以这样做:return Regex.Replace(input ?? string.Empty, @"[^A-z0-9\-]", "");
    【解决方案5】:

    我相信你可以再花一点时间想出更好的东西,但这会给你一个好主意:

    public string NumberOrLetterOnly(string s)
    {
        string rtn = s;
        for (int i = 0; i < s.Length; i++)
        {
            if (!char.IsLetterOrDigit(rtn[i]) && rtn[i] != '-')
            {
                rtn = rtn.Replace(rtn[i].ToString(), " ");
            }
        }
        return rtn.Replace(" ", "");
    }
    

    【讨论】:

    • 哦,我刚刚注意到他不想要循环。除了正则表达式解决方案看起来更好。不过我不会删除我的帖子,因为其中一些方法可能仍然有用
    【解决方案6】:

    为什么不直接使用替换呢? Trimstart 只会删除列表中的前导字符...

    【讨论】:

    • 只需要写一个循环扫描然后删除
    猜你喜欢
    • 2011-08-22
    • 1970-01-01
    • 2022-09-23
    • 2022-07-04
    • 1970-01-01
    • 2021-10-03
    • 2020-06-14
    • 2020-06-08
    相关资源
    最近更新 更多