Праверка, калі кожны знак у C # радкі гэта той жа знак

Пачынаючы з любой радкі, мне трэба высветліць, ці ўтрымоўвае гэты радок адзін або некалькі асобнікаў толькі названага аднаго знака. Напрыклад «£££££» будзе праходзіць мой тэст, «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
        }
    }

Гэта працуе, як і варта было чакаць, але я не магу дапамагчы, але адчуваю, што я мог бы прапусціць трук тут. Ёсць лепш, больш коратка, спосаб зрабіць гэта, што не ахвяруе яснасць вышэй?

0
будзе string.IndexOfAny() быць карысным?
дададзена аўтар David, крыніца
Я хачу праверыць для канкрэтнага персанажа, я выкарыстаў «Е» у якасці прыкладу тут, але гэта можа быць любы канкрэтны характар.
дададзена аўтар Jason, крыніца
Я рэдагаваў сваё пытанне, каб гэта больш выразна.
дададзена аўтар slim, крыніца
З вашага апісання «AAAAA» пройдзе. Але ваш код праходзіць толькі для радкоў, якія змяшчаюць толькі «Е». Што вы хочаце?
дададзена аўтар slim, крыніца

9 адказы

Вы проста праверыць з простым кодам, ці мае радок адзін і той жа характар:

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

Edit:

Калі вам неабходна праверыць радок утрымлівае адзін або некалькі асобнікаў толькі названага аднаго знака, вы можаце выкарыстоўваць Усе :

if (input.All(c => c == specificChar))
{
   //Pass
}
9
дададзена
Гэта вельмі акуратна.
дададзена аўтар hattenn, крыніца
Які, верагодна, не будзе праблемай, так як у апошні раз я сутыкаўся радок 2GB, пачынаючы з AAB не было ... ніколі.
дададзена аўтар hattenn, крыніца
Для гэтага спатрэбіцца перагрузка Distinct, якая прымае IEqualityComparer <�сімвал>, так што тэст для канкрэтнага характару можа быць выкананы, я думаю.
дададзена аўтар Jason, крыніца
@ Knaģis: так, але прадукцыйнасць была б трывіяльнай, калі вы не вельмі доўгая радок, вы можаце атрымаць вельмі просты код з высокай дыскрэтнасцю
дададзена аўтар Cuong Le, крыніца
так, гэта вельмі мала, але там не будзе прадукцыйнасць у параўнанні з аўтарамі арыгінальнага кода.
дададзена аўтар Knaģis, крыніца
на мой i7 100Mb выпадковая радок займае каля 3 секунд. Прадукцыйнасць, здаецца, лінейныя па даўжыні радка.
дададзена аўтар Knaģis, крыніца
Хоць, калі ў вас ёсць радок 2 Гб, якая пачынаецца з ааЪ ... , гэта зойме некаторы час;)
дададзена аўтар Oded, крыніца
+1. Вельмі добры адказ.
дададзена аўтар Mitch Wheat, крыніца
Справа ў тым, што эфектыўны алгарытм будзе пад заклад на першым несогласующейс характару. Гэта адзін штампуе праз усю радок, нават калі першы сімвал з'яўляецца неадпаведнасць. Рашэнне ўсё() выдатна, хоць.
дададзена аўтар slim, крыніца

Use Enumerable.All Method

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

This would be efficient than using Distinct and Count()

У вашым выпадку гэта можа быць:

string source = "any string";
char validCharacter = '£';
bool result = source.Length > 0 && source.All(r=> r == validCharacter);
3
дададзена
Усе гэтыя гады з выкарыстаннем перечислимых метадаў, і я ніколі не ведаў, што там было ўсё (!) Дзякуючы.
дададзена аўтар Jason, крыніца

Выкарыстоўвайце Distinct() , каб выдаліць дублікаты і параўнаць падлік знакаў.

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

<�Моцны> Змяніць

Я няправільна зразумеў і падумаў, што гэта дублікат любога сімвала ў тэставай паслядоўнасці. Наступнае дакладна для «аднаго або некалькіх асобнікаў толькі адзін знак».

mystring.Distinct().Count() == 1
2
дададзена
"А" .Count ()> "а" .distinct (). Count() = ілжыва, што з'яўляецца правільным, паколькі няма ніякіх дублікатаў. Як гэта правал?
дададзена аўтар Oliver, крыніца
Збой для радкоў з даўжынёй 1
дададзена аўтар Jan, крыніца

Вось адзін са спосабаў зрабіць гэта:

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

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

Things to note: immediate fail if the first character doesn't match. string already implements IEnumerable, so no need to use ToCharArray with the extra allocations. The loop starts at index 1, always comparing to the first item and breaking as soon as it fails.

Гэта, верагодна, будзе больш эфектыўным для доўгіх радкоў, чым Distinct .

2
дададзена
гэта, верагодна, выканаць трохі хутчэй, калі б спраўджваць validCharacter , а не крыніца [0] .
дададзена аўтар Knaģis, крыніца
@ Knaģis - Праўда. Няма неабходнасці для гэтага пошуку.
дададзена аўтар Oded, крыніца
string test1 = "Test";
string test2 = "TTTT";

test1.All(a => a == test1[0]);
test2.All(a => a == test2[0]);
1
дададзена

Your code is probably going to be the fastest, you could compact it somewhat by using a for instead of a while

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

З іншага боку, вось яшчэ неэфектыўна, але больш кампактны спосаб (бо ён стварае новы радок у памяці і правярае супраць):

if (source == new String('£', source.Length)) {
   //valid
}
1
дададзена

У вашым алгарытме вам не трэба .ToCharArray() . Проста атрымаць сімвал, выкарыстоўваючы зыходны [індэкс] . Такім чынам, вы будзеце чытаць толькі памяць і чытання кожнага сімвала толькі адзін раз.

Ваш код з'яўляецца аптымальным рашэннем. Ёсць шмат трукаў з выкарыстаннем LINQ, але большасць з іх будзе працаваць значна горш. Любыя трукі з кодам, як source.Trim (крыніца [0]) прывядуць да непатрэбнага стварэнню новых радкоў і, такім чынам, і ў горшым выкананні.

See the answer from Oded♦ that shortens your existing code.

1
дададзена

Вы можаце паспрабаваць гэта:

 string str = "test";
            char b = '£';
            bool isValid = false;
            foreach (char a in str) 
            {
                if (!a.Equals(b)) 
                {
                    isValid = false;
                }
            }
0
дададзена
if(Regex.IsMatch(candidate, "^£+$")) {
  //whatever it is you want to do
}

... або, вядома ...

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

Regex.Escape() is there in case validChar is a character with meaning in regular expressions, like *, . etc.

Гэтыя кароткія, дэкларатыўныя (да таго часу, як чытач разумее рэгулярныя выразы), эфектыўная прадукцыйнасць маштабуецца для доўгіх радкоў, а ідыёмы распаўсюджваецца на больш складаныя ўзоры.

0
дададзена
другі варыянт мае патрэбу ў Regex.Escape ...
дададзена аўтар Knaģis, крыніца
@ Knaģis добры ўлоў, дзякуй.
дададзена аўтар slim, крыніца