0

I'm trying to find a way to simplify the comparison cases of booleans. Currently, there are only three (as shown below), but I'm about to add a 4th option and this is getting very tedious.

bracketFirstIndex = message.indexOf('[');
mentionFirstIndex = message.indexOf('@');
urlFirstIndex = message.indexOf(urlStarter);

bool startsWithBracket = (bracketFirstIndex != -1);
bool startsWithAtSymbol = (mentionFirstIndex != -1);
bool startsWithUrl = (urlFirstIndex != -1);     

if (!startsWithBracket)
{
    if (!startsWithAtSymbol)
    {
        if (!startsWithUrl)
        {
            // No brackets, mentions, or urls. Send message as normal
            cursor.insertText(message);
            break;
        }
        else
        {
            // There's a URL, lets begin!
            index = urlFirstIndex;
        }
    }
    else
    {
        if (!startsWithUrl)
        {
            // There's an @ symbol, lets begin!
            index = mentionFirstIndex;
        }
        else
        {
            // There's both an @ symbol and URL, pick the first one... lets begin!
            index = std::min(urlFirstIndex, mentionFirstIndex);
        }
    }
}
else
{
    if (!startsWithAtSymbol) 
    {
        // There's a [, look down!
        index = bracketFirstIndex;
    }
    else
    {
        // There's both a [ and @, pick the first one... look down!
        index = std::min(bracketFirstIndex, mentionFirstIndex);
    }

    if (startsWithUrl)
    {
        // If there's a URL, pick the first one... then lets begin!
        // Otherwise, just "lets begin!"
        index = std::min(index, urlFirstIndex);
    }
}

Is there a better/more simpler way to compare several boolean values, or am I stuck in this format and I should just attempt to squeeze in the 4th option in the appropriate locations?

ZeldaZach
  • 478
  • 1
  • 9
  • 18
  • 1
    It looks like you are parsing some text... you could potentially simplify this with a regular expression or using a parser-generator. – Michael Aaron Safyan Jul 12 '15 at 00:41
  • @MichaelAaronSafyan Can you elaborate a little further on the REGEX plan / parser-generator (I've never heard of this wording). – ZeldaZach Jul 12 '15 at 00:44
  • 1
    @ZeldaZach Can you tell us what you are trying to parse? It seems its some sort of e-mail or URL, but I don't recall `[` participating on any of those. If you can be more specific about your problem we might be able to help with regex. – Havenard Jul 12 '15 at 00:46
  • @Havenard This is an in-program chat service, which we have special rules for different things. For example, you can @ mention somebody, post a url (http://example.com), use a card look up function [[card name]], and I'm working on adding a highlight function right now, but I'd like to see if I can simplify the statements – ZeldaZach Jul 12 '15 at 00:49
  • @ZeldaZach So it seems they are completely separete things. You should treat them separately aswell. Anyway, I'd recommend using one or two `std::regex_token_iterator`, one for the @mentions and another for URLs, including [URLs with custom text](http://stackoverflow.com/a/22617942/156811). See example of `std::regex_token_iterator` here: http://stackoverflow.com/a/22617942/156811 Unless its a simple matter of highlighting text or building links, in this case a simple `std::regex_replace` should suffice. – Havenard Jul 12 '15 at 00:59
  • 1
    The notion that "starts with X" = "there is an X somewhere" sounds dubious to me. I suspect the presented code is not correct. – Cheers and hth. - Alf Jul 12 '15 at 01:10
  • Also, of the eight possible combinations of 3 startsWithSomething boolean values, this code checks 7. For example, with the starts with bracket case the code checks if maybe the string starts with at symbol. It might be because of the peculiar "starts with" notion, but I suspect that this is simply incorrect, that a string can't "start with" both square bracket and at sign, for example, i.e. that the different cases are *mutually exclusive*-. – Cheers and hth. - Alf Jul 12 '15 at 01:14

2 Answers2

3

Some type of text processing are fairly common, and for those, you should strongly consider using an existing library. For example, if the text you are processing is using the markdown syntax, consider using an existing library to parse the markdown into a structured format for you to interpret.

If this is completely custom parsing, then there are a few options:

  • For very simple text processing (like a single string expected to be in one of a few formats or containing a piece of subtext in an expected format), use regular expressions. In C++, the RE2 library provides very powerful support for matching and extracting usign regexes.

  • For more complicated text processing, such as data spanning many lines or having a wide variety of content / syntax, consider using an existing lexer and parser generator. Flex and Bison are common tools (used together) to auto-generate logic for parsing text according to a grammar.

  • You can, by hand, as you are doing now, write your own parsing logic.

If you go with the latter approach, there are a few ways to simplify things:

  1. Separate the "lexing" (breaking up the input into tokens) and "parsing" (interpreting the series of tokens) into separate phases.

  2. Define a "Token" class and a corresponding hierarchy representing the types of symbols that can appear within your grammar (like RawText, Keyword, AtMention, etc.)

  3. Create one or more enums representing the states that your parsing logic can be in.

  4. Implement your lexing and parsing logic as a state machine that transforms the state given the current state and the next token or letter. Building up a map from (state, token type) to next_state or from (state, token type) to handler_function can help you to simplify the structure.

rici
  • 234,347
  • 28
  • 237
  • 341
Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
0

Since you are switching only on the starting letter, use cases:

enum State { Start1, Start2, Start3, Start4};
State state;
if (startswithbracket) {
   state = Start1;
} else {
.
.
.
}

switch (state) {
   case Start1:
      dosomething;
      break;
   case Start2:
      .
      .
      .
 }

More information about switch syntax and use cases can be found here.

XapaJIaMnu
  • 1,408
  • 3
  • 12
  • 28