3
\$\begingroup\$

It is a practice from the site edabit.com and you have to check if the input is valid. That is the original task:

Given an RGB(A) CSS color, determine whether its format is valid or not. Create a function that takes a string (e.g. "rgb(0, 0, 0)") and return True if it's format is correct, otherwise return False.

The rules are shown in the testing code:

# True Tests
Test.assert_equals(valid_color('rgb(0,0,0)'), True, 'rgb lowest valid numbers')
Test.assert_equals(valid_color('rgb(255,255,255)'), True, 'rgb highest valid numbers')
Test.assert_equals(valid_color('rgba(0,0,0,0)'), True, 'rgba lowest valid numbers')
Test.assert_equals(valid_color('rgba(255,255,255,1)'), True, 'rgba highest valid numbers')
Test.assert_equals(valid_color('rgba(0,0,0,0.123456789)'), True, 'alpha can have many decimals')
Test.assert_equals(valid_color('rgba(0,0,0,.8)'), True, 'in alpha the number before the dot is optional')
Test.assert_equals(valid_color('rgba(   0 , 127 , 255 , 0.1 )'), True, 'whitespace is allowed around numbers (even tabs)')
Test.assert_equals(valid_color('rgb(0%,50%,100%)'), True, 'numbers can be percentages')

# False Tests
Test.assert_equals(valid_color('rgb(0,,0)'), False, 'INVALID: missing number')
Test.assert_equals(valid_color('rgb (0,0,0)'), False, 'INVALID: whitespace before parenthesis')
Test.assert_equals(valid_color('rgb(0,0,0,0)'), False, 'INVALID: rgb with 4 numbers')
Test.assert_equals(valid_color('rgba(0,0,0)'), False, 'INVALID: rgba with 3 numbers')
Test.assert_equals(valid_color('rgb(-1,0,0)'), False, 'INVALID: numbers below 0')
Test.assert_equals(valid_color('rgb(255,256,255)'), False, 'INVALID: numbers above 255')
Test.assert_equals(valid_color('rgb(100%,100%,101%)'), False, 'INVALID: numbers above 100%')
Test.assert_equals(valid_color('rgba(0,0,0,-1)'), False, 'INVALID: alpha below 0')
Test.assert_equals(valid_color('rgba(0,0,0,1.1)'), False, 'INVALID: alpha above 1')

I fear that my solution is not very elegant, efficent or short:

def create_rgbA_tuple(color):
    indexBracket1 = color.rfind("(")
    save = color[0] + color[1] + color[2] + color[3]
    if save != 'rgb(' and save != 'rgba':
        return False
    indexBracket2 = color.rfind(")")
    bracketArea = ""
    for i in range(indexBracket1 + 1, indexBracket2):
        bracketArea = bracketArea + color[i]

    bracketArea = bracketArea.split(',')  # bracketArea is now an Array (r,g,b/A)
    if len(bracketArea) == 4 and save != 'rgba' or len(bracketArea) == 3 and save != 'rgb(':
        return False
    try:
        for i in range(len(bracketArea)):
            bracketArea[i] = float(bracketArea[i])
    except:
        try:
            for i in range(len(bracketArea)):
                if bracketArea[i][-1] == "%":
                    bracketArea[i] = int(bracketArea[i].strip('%')) / 100 * 255
                else:
                    return False
        except:
            return False
    return bracketArea


def valid_color(color):
    rgb = create_rgbA_tuple(color)
    if not rgb:
        return False
    for i in range(3):
        if int(rgb[i]) < 0 or int(rgb[i]) > 255:
            return False

    if color[3] == "a":  # if rgbA
        if rgb[3] < 0 or rgb[3] > 1:
            return False
    return True
```
\$\endgroup\$
2
\$\begingroup\$

One thing the tests don't indicate is whether space is allowed before/after the color string. I'm inclined to be generous, so I'd suggest just discarding any space before you start:

color = color.strip()

Next, you are doing a lot of work to replace some python built-in functions. Before you do anything else, you should probably read the String Methods documentation to see what tools are available to you.

Try something like:

is_rgb = color.startswith('rgb(')
is_rgba = color.startswith('rgba(')

if not is_rgb and not is_rgba:
    return False

if not color.endswith(')'):
    return False

# strip off prefix "...(" and suffix ")"   
color = color[color.index('(') + 1:-1]

You can use .endswith to check for percent signs, also.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you for your advise! You are right these inbuilt functions are far more elegant, I guess I'll start learning some. \$\endgroup\$ – Jonas Aug 7 '20 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.