检查字符串是否包含10个字符之一


107

我正在使用C#,我想检查一个字符串是否包含十个字符之一,*,&,#等。

什么是最好的方法?


1
您是否要查看其中是否存在任何字符,或者其中是否包含这些字符中的“一个”(即:正好一个),并且仅包含一个?
Reed Copsey

Answers:


210

在我看来,以下是最简单的方法:

var match = str.IndexOfAny(new char[] { '*', '&', '#' }) != -1

或者以一种可能更易于阅读的形式:

var match = str.IndexOfAny("*&#".ToCharArray()) != -1

根据上下文和所需的性能,您可能会或可能不想缓存char数组。


当实例化char数组时,可以省略类型并将其推断出来。
Palec

40

正如其他人所说,请使用IndexOfAny。但是,我将以这种方式使用它:

private static readonly char[] Punctuation = "*&#...".ToCharArray();

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny(Punctuation) >= 0;
}

这样,您最终就不会在每次调用时都创建一个新的数组。与一系列字符文字IMO相比,该字符串也更易于扫描。

当然,如果只使用一次,那么浪费的创建就不成问题,您可以使用:

private const string Punctuation = "*&#...";

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny(Punctuation.ToCharArray()) >= 0;
}

要么

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny("*&#...".ToCharArray()) >= 0;
}

这实际上取决于您发现哪个更具可读性,是否要在其他地方使用标点符号以及该方法将被调用的频率。


编辑:这是里德·科普西(Reed Copsey)的方法的一种替代方法,用于确定字符串是否恰好包含一个字符。

private static readonly HashSet<char> Punctuation = new HashSet<char>("*&#...");

public static bool ContainsOnePunctuationMark(string text)
{
    bool seenOne = false;

    foreach (char c in text)
    {
        // TODO: Experiment to see whether HashSet is really faster than
        // Array.Contains. If all the punctuation is ASCII, there are other
        // alternatives...
        if (Punctuation.Contains(c))
        {
            if (seenOne)
            {
                return false; // This is the second punctuation character
            }
            seenOne = true;
        }
    }
    return seenOne;
}

我认为如果性能有问题,则值得缓存char数组,但是根据上下文的不同,这也许也不值得。
Noldorin

1
是的,如果您仅在将要执行的方法中使用它,则可能不值得。但是,我认为它提高了可读性以及性能。ToCharArray当然,如果需要,您可以使用“内联”形式。
乔恩·斯基特

1
@佳能:这是多大的?对于非常小的集合,我希望Array.Contains更快。对于大型组合,HashSet可能会赢得胜利。
乔恩·斯基特

5

如果您只想查看它是否包含任何字符,我建议使用string.IndexOfAny,如在其他地方建议的那样。

如果你想验证字符串包含只有一个的十个字符,只有一个,那么它变得有点复杂。我相信最快的方法是检查一个交叉点,然后检查重复项。

private static char[] characters = new char [] { '*','&',... };

public static bool ContainsOneCharacter(string text)
{
    var intersection = text.Intersect(characters).ToList();
    if( intersection.Count != 1)
        return false; // Make sure there is only one character in the text

    // Get a count of all of the one found character
    if (1 == text.Count(t => t == intersection[0]) )
        return true;

    return false;
}

是的-我想在这种情况下,单循环可能会更快,尤其是在标点集很少的情况下。我很好奇尝试用大字符串测试它,看看哪个确实更快。
Reed Copsey

1
我认为找到两个字符串的交集无论如何都必须逐个字符地进行,所以我看不出它会更快。选择“提前退出”。假设文本长度为一百万个字符,但前两个字符均为“ *” :)
Jon Skeet


1
var specialChars = new[] {'\\', '/', ':', '*', '<', '>', '|', '#', '{', '}', '%', '~', '&'};

foreach (var specialChar in specialChars.Where(str.Contains))
{
    Console.Write(string.Format("string must not contain {0}", specialChar));
}

0

感谢大家!(主要是乔恩!):这让我可以这样写:

    private static readonly char[] Punctuation = "$€£".ToCharArray();

    public static bool IsPrice(this string text)
    {
        return text.IndexOfAny(Punctuation) >= 0;
    }

因为我在寻找一种检测特定字符串实际上是价格还是句子的好方法,例如“显示得太低”。


2
我知道这很古老,但是要明确地说,这不是匹配货币的特别好方法...如果您有人写“ Ke $ ha”,它将作为价格进行匹配...而是参考一种正确的方法:检测这里定义的货币stackoverflow.com/questions/7214513/...
mcse3010
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.