0

从任何字符串开始,我需要确定该字符串是否包含一个或多个仅包含指定单个字符的实例。例如“£££££”会通过我的测试,“wertf”会失败。我采取的方法如下:

string source = "any string";
char[] candidate = source.ToCharArray();
char validCharacter = '£';

    if (candidate.Length > 0)
    {
        // (code removed) if candidate length = 1 then just test candidate[0] against validCharacter
        bool isValid = true;
        int index = 0;

        while (index < candidate.Length - 1)
        {
            if (candidate [index] != validCharacter )
            {
                isValid = false;
                break;
            }

            index++;
        }

        if (isValid)
        {
            // success, do what needs doing
        }
    }

正如您所期望的那样,这很有效,但我不禁觉得我可能在这里错过了一个技巧。有没有更好,更简洁的方法来做到这一点,而不会牺牲上述的清晰度?

4

9 回答 9

9

您只需使用更简单的代码检查字符串是否具有相同的字符:

if (source.Distinct().Count() == 1)
{
    // Pass
}

编辑:

如果您需要检查字符串是否包含一个或多个仅指定单个字符的实例,您可以使用All

if (input.All(c => c == specificChar))
{
    // Pass
}
于 2013-05-23T10:05:25.113 回答
3

采用Enumerable.All<TSource> Method

bool result = (str.Length > 0 && str.All(r=> r == str[0]));

这比使用DistinctCount()

对于您的情况,它可以是:

string source = "any string";
char validCharacter = '£';
bool result = source.Length > 0 && source.All(r=> r == validCharacter);
于 2013-05-23T10:05:31.707 回答
2

用于Distinct()删除重复项并比较字符数。

var pass = mystring.Count() > mystring.Distinct().Count();

编辑

我误读并认为它与测试字符串中的任何字符重复。以下对于“只有一个字符的一个或多个实例”是正确的。

mystring.Distinct().Count() == 1
于 2013-05-23T10:05:28.190 回答
2

这是执行此操作的一种方法:

if(source[0] != validCharacter) return false;

bool isValid = true;
for(int i = 1 ; i < source.Length; i++)
{
  if(validCharacter != source[i])
  {
    isValid = false;
    break;
  }
}

注意事项:如果第一个字符不匹配,则立即失败。string已经实现IEnumerable<char>,因此无需使用ToCharArray额外的分配。循环从索引 1 开始,始终与第一项进行比较,并在失败时立即中断。

对于长字符串,这可能比Distinct.

于 2013-05-23T10:06:29.780 回答
1
string test1 = "Test";
string test2 = "TTTT";

test1.All(a => a == test1[0]);
test2.All(a => a == test2[0]);
于 2013-05-23T10:06:40.663 回答
1

在您的算法中,您不需要.ToCharArray(). 只需使用 . 检索字符source[index]。这样,您将只读取内存并读取每个字符一次。

您的代码是最佳解决方案。使用 LINQ 有很多技巧,但大多数都会表现得更差。任何类似代码的技巧source.Trim(source[0])都会导致不必要的新字符串创建,从而导致性能下降。

请参阅 Oded♦ 的答案,它可以缩短您现有的代码。

于 2013-05-23T10:07:35.893 回答
1

您的代码可能是最快的,您可以使用 afor而不是 a 来压缩它while

for (int i = 0; i < source.Length; i++) {
    // existing equality check
}

或者,这是另一种低效但更紧凑的方法(因为它在内存中创建一个新字符串并进行检查):

if (source == new String('£', source.Length)) {
    // valid
}
于 2013-05-23T10:11:02.063 回答
0

你可以试试这个:

 string str = "test";
            char b = '£';
            bool isValid = false;
            foreach (char a in str) 
            {
                if (!a.Equals(b)) 
                {
                    isValid = false;
                }
            }
于 2013-05-23T10:08:14.667 回答
0
if(Regex.IsMatch(candidate, "^£+$")) {
   // whatever it is you want to do
}

……或者当然……

if(Regex.IsMatch(candidate, "^" + Regex.Escape(validChar) + "+$") { ... }

Regex.Escape()是否存在validChar正则表达式中具有含义的字符,例如*.

这些是简短的、声明性的(只要读者理解正则表达式)、高效、性能可扩展到长字符串,并且成语扩展到更复杂的模式。

于 2013-05-23T10:16:26.657 回答