user2715877
user2715877

Reputation: 543

JavaScript Regular Expression (If and only if)

I just finished all the "Easy" CoderByte challenges and am now going back to see if there are more efficient ways to answer the questions. I am trying to come up with a regular expression for "SimpleSymbol".

(Have the function SimpleSymbols(str) take the str parameter being passed and determine if it is an acceptable sequence by either returning the string true or false. The str parameter will be composed of + and = symbols with several letters between them (ie. ++d+===+c++==a) and for the string to be true each letter must be surrounded by a + symbol. So the string to the left would be false. The string will not be empty and will have at least one letter.)

I originally answered the question by traversing through the whole string, when a letter is found, testing on either side to see if a "+" exists. I thought it would be easier if I could just test the string with a regular expression like,

str.match(/\+[a-zA-Z]\+/g)

This doesn't quite work. I am trying to see if the match will ONLY return true if the condition is met on ALL of the characters in the string. For instance the method will return true on the string, "++d+===+c++==a", due to '+d+' and '+c+'. However, based on the original question it should return false because of the 'a' and no surrounding '+'s.

Any ideas?

Upvotes: 1

Views: 3078

Answers (4)

p.s.w.g
p.s.w.g

Reputation: 149020

The problem is that + is a special character in regular expressions. It's a quantifier that means 'one or more of the previous item'. You can represent a literal + character by escaping it, like this:

str.match(/\+[a-zA-Z]\+/g)

However, this will return true if any set of characters is found in the string matching that pattern. If you want to ensure that there are no other characters in the string which do not match that pattern you could do something like this:

str.match(/^([=+]*\+[a-zA-Z](?=\+))+[=+]*$/)

This will match, any number of = or + characters, followed by a literal + followed by a Latin letter, followed by a literal +, all of which may be repeated one or more times, followed by any number of = or + characters. The ^ at the beginning and the $ at the end matches the start and end of the input string, respectively. This ensures that no other characters are allowed. The (?=\+) is a look-ahead assertion, meaning that the next character must be a literal +, but is not considered part of the group, this means it can be rematched as the leading + in the next match (e.g. +a+b+).

Upvotes: 1

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89557

/^[=+]*\+[a-z](?=\+)(?:\+[a-z](?=\+)|[+=]+)*$/i.test(str)

pattern details:

^                 # anchor, start of the string
[=+]*             # 0 or more = and +
\+ [a-z] (?=\+)   # imposed surrounded letter (at least one letter condition)
(?:               # non capturing group with:
    \+[a-z](?=\+) # surrounded letter 
  |               # OR
    [=+]+         # + or = characters (one or more)
)*                # repeat the group 0 or more times
$                 # anchor, end of the string

To allow consecutive letters like +a+a+a+a+a+, I use a lookahead assertion to check there is a + symbol after the letter without match it. (Thanks to ridgrunner for his comment)

Example:

var str= Array('+==+u+==+a', '++=++a+', '+=+=', '+a+-', '+a+a+');
for (var i=0; i<5; i++) {
    console.log(/^[=+]*\+[a-z](?=\+)(?:\+[a-z](?=\+)|[+=]+)*$/i.test(str[i]));
}

Upvotes: 0

ridgerunner
ridgerunner

Reputation: 34395

Interesting problem!

String requirements:

  • String must be composed of only +, = and [A-Za-z] alpha chars.
  • Each and every alpha char must be preceded by a + and followed by a +.
  • There must be at least one alpha char.

Valid strings:

"+A+"
"++A++"
"=+A+="
"+A+A+"
"+A++A+"

Invalid strings:

+=+= # Must have at least one alpha.
+A+&+A+ # Non-valid char.
"+A" # Alpha not followed by +.
"A+" # Alpha not preceded by +.

Solution:

^[+=]*(?:\+[A-Z](?=\+)[+=]*)+$ (with i ignorecase option set)

Here's how I'd do it: (First in a tested python script with fully commented regex)

import re
def isValidSpecial(text):
    if re.search(r"""
        # Validate special exercise problem string format.
        ^          # Anchor to start of string.
        [+=]*      # Zero or more non-alphas {normal*).
        (?:        # Begin {(special normal*)+} construct.
          \+[A-Z]  # Alpha but only if preceded by +
          (?=\+)   # and followed by + {special} .
          [+=]*    # More non-alphas {normal*).
        )+         # At least one alpha required.
        $          # Anchor to end of string.
        """, text, re.IGNORECASE | re.VERBOSE):
        return "true"
    else:
        return "false"

print(isValidSpecial("+A+A+"))

Now here is the same solution in JavaScript syntax:

function isValidSpecial(text) {
    var re = /^[+=]*(?:\+[A-Z](?=\+)[+=]*)+$/i;
    return (re.test(text)) ? "true" : "false";
}

Upvotes: 0

vroomfondel
vroomfondel

Reputation: 3106

EDIT: @Marc brought up a very good point. The easiest way to do this is to search for violations using

[^+][a-zA-Z]|[a-zA-Z][^+]

or something like it. This will find all violations of the rule -- times when a letter appears next to something other than a +. If this matches, then you can return false, knowing that there exist violations. Else, return true.

Original answer:

Here's a regex -- I explain it below. Remember that you have to escape +, because it is a special character!

^([^a-zA-Z+]|(\+[a-zA-Z]\+)|[+])*$

^ // start of the string
[^a-zA-Z+] // any character except a letter or a + (1)
| // or
(\+[a-zA-Z]\+) // + (letter) + (2)
| //or
[+] // plus (3)
)*$ // repeat that pattern 0 or more times, end
  • The logic behind this is: skip all characters that aren't relevant in your string. (1)
  • If we have a + (letter) +, that's fine. capture that. (2)
  • if we have a + all by itself, that's fine too. (3)
  • A letter without surrounding + will fail.

Upvotes: 1

Related Questions