开发者

Grouping Logical Operators (Multiple Sets of Conditions) in a do {} while () loop?

I currently have the following loop:

do {
       checkedWord = articleWords.Dequeue().TrimEnd('?', '.', ',', '!');
       correct = _spellChecker.CheckWord(checkedWord);
   } while (correct && articleWords.Count > 0);

I am queuing up the words from an array that was split from a textbox with ' ' as the separator. The loop works fine, except for I don't want any blank entries "" or really anything non alpha-numeric to stop the loop. Currently if there's more than one space between the words then the loop ends and it continues on to get word suggestions from the spellchecker.

If I do while (correct && articleWords.Count > 0 || checkedWord == ""); then it'll skip any blank queue entries, but it still hangs up on things like new lines - so if the textbox that it loads from contains a couple of paragraphs it screws up at the newline separating the two. I've also tried while (correct && articleWords.Count > 0 || !Char.IsLetterOrDigit(checkedWord, 0)); but that also doesn't work.

Question 1: Can you group conditions like (statement1 == true && count > 0) || (statement1 == false && Char.IsLetterOrDigit(char))? - Meaning that all of the conditions in the first grouping must be met OR all of the conditions in the second set must be.

Question 2: I want my loop to continue progressing until an actual spelling error is found, and for it to ignore things like empty queue entries, as well as anything that's not an alpha-numeric character at the beginning of the string.

I suspect that I'm close with the Char.IsLetterOrDigit bit, but have t开发者_如何学Goo figure out how to do it correctly.

Let me know if more info is required.

Thanks!


You should not use composite loop condition, a good practice is usage while loop with easy general condition and 'break' in loop body when you should leave it.

You can use some thing like this:

public void Test()
{
    var separators = new[] { ' ', '\t', '\r', '\x00a0', '\x0085', '?', ',', '.', '!' };

    var input = "Test  string, news112!  news \n next, line! error in error word";          
    var tokens = new Queue<string>(input.Split(separators, StringSplitOptions.RemoveEmptyEntries));

    string currentWord = null;

    while (tokens.Any())
    {
        currentWord = tokens.Dequeue();
        if (currentWord.All(c => Char.IsLetterOrDigit(c)))
        {
            if (!CheckSpell(currentWord))
            {
                break;
            }
        }
    }
}

public bool CheckSpell(string word)
{
    return word != null && word.Length > 0 && word[0] != 'e';
}


If your goal is to find the first error, you can skip the while loop and do the following:

var firstError = tokens.Where(t => t.All(Char.IsLetterOrDigit) && !_spellChecker.CheckWord(t)).FirstOrDefault();


  1. So long as you have a valid boolean expression, you can do that without an issue. This is something that is very easy to test.

  2. To use Char.IsLetterOrDigit you will need to loop over each character in the string and test it.


When it comes to text selections you should use regular expressions. It is very powerfull and fast framework for text queries. It is capable of doing it's job with O(n) complexity. It helps you because you don't have to think how you will select your text values you just specify what you need

Try this code. The pattern part @"\w+" means that I want to select all groups of alphanumeric symbols whose length > 1. If I'd wanted to select all words that start with letter 't' than I would write @"t\w+".

using System;
using System.Text;
using System.Text.RegularExpressions;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            string str = "The quick brown fox jumps over the lazy dog";

            Regex regex = new Regex(@"\w+", RegexOptions.Compiled);


            for (Match match = regex.Match(str); match.Success; match = match.NextMatch())
            {
                Console.WriteLine(match.Value);
            }
        }
    }
}


Q1. Absolutely. Just make sure your groupings are properly separated.

Q2. For performance and clarity, I would use REGEX to clean your input before queuing:

using System.Text.RegularExpressions;
...
string input = GetArticle(); // or however you get your input

input = Regex.Replace(input, @"[^0-9\w\s]", string.Empty);

// not sure what your separators but you can always
// reduce multiple spaces to a single space and just split
// on the single space
var articleWords = new Queue<string>(input.Split( ... ));

do {
     checkedWord = articleWords.Dequeue();

     // put your conditional grouping here if you want
     if(!_spellChecker.CheckWord(checkedWord)) {
          // only update "correct" if necessary - writes are more expensive =)
          // although with the "break" below you shouldn't need "correct" anymore
          // correct = false;

          // in case you want to raise an event - it's cleaner =)
          OnSpellingError(checkWord);

          // if you want to stop looping because of the error
          break;
     }
}
while(articleWords.Count > 0);

I wouldn't use Char.IsLetterOrDigit as I think that would be slower...besides, with the REGEX in the beginning you should have taken care of the entries that aren't characters or digits.

EDIT Adding LINQ response

On second thought, I think you're just trying to find spelling errors so how about this?

using System.Text.RegularExpressions;
...
string input = GetArticle(); // or however you get your input

// clean up words from punctuation
input = Regex.Replace(input, @"[^0-9\w\s]", string.Empty);

// trim whitespace
input = Regex.Replace(c, @"\s+", @" ");

var errors = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).All(w => !_spellChecker.CheckWord(w));

Then you can just do whatever you want with the errors =) Or you can just use a .Any if you just want to know whether there exists a spelling mistake at all.


Q1: Sure, it's possible to group conditions like that.

Q2: What about something like this?

string[] articleWords = textBoxText.Split(' ');
articleWords = articleWords.Select(a => a.Trim()).ToArray();    // remove all whitespaces (blanks, linebreaks)
articleWords = articleWords.Where(a => !string.IsNullOrEmpty(a)).ToArray(); // remove empty strings

bool correct = false;
bool spellingErrorFound = false;
for (int i = 0; i < articleWords.Length; i++)
{
    string checkedWord = articleWords[i].TrimEnd('?', '.', ',', '!');
    correct = _spellChecker.CheckWord(checkedWord);

    if (!correct)
        spellingErrorFound = true;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜