How to Parse HTML/CSS Colors in Java

2 min read 499 words

Table of Contents

The challenge

In this challenge, you parse RGB colors represented by strings. The formats are primarily used in HTML and CSS. Your task is to implement a function that takes a color as a string and returns the parsed color as a map (see Examples).

Inputs:

The input string represents one of the following:

  • 6-digit hexadecimal – “#RRGGBB”
    e.g. “#012345”, “#789abc”, “#FFA077”
    Each pair of digits represents a value of the channel in hexadecimal: 00 to FF
  • 3-digit hexadecimal – “#RGB”
    e.g. “#012”, “#aaa”, “#F5A”
    Each digit represents a value 0 to F which translates to 2-digit hexadecimal: 0->00, 1->11, 2->22, and so on.
  • Preset color name
    e.g. “red”, “BLUE”, “LimeGreen”
    You have to use the predefined map PRESET_COLORS (JavaScript, Python, Ruby), presetColors (Java, C#, Haskell), or preset-colors (Clojure). The keys are the names of preset colors in lower-case and the values are the corresponding colors in 6-digit hexadecimal (same as 1. “#RRGGBB”).

Examples:

parse("#80FFA0") === new RGB(128, 255, 160))
parse("#3B7") === new RGB( 51, 187, 119))
parse("LimeGreen") === new RGB( 50, 205,  50))

// RGB class is defined as follows:
final class RGB {
    public int r, g, b;
    
    public RGB();
    public RGB(int r, int g, int b);
}

The solution in Java code

Option 1:

import java.util.Map;
import java.awt.Color;

public class HtmlColorParser {
    private final Map<String, String> presetColors;
    public HtmlColorParser(Map<String, String> presetColors) {
        this.presetColors = presetColors;
    }
    public RGB parse(String color) {
        if (color.charAt(0) != '#') color = nameFixer(color);
        if (color.length() < 7) color = stringFixer(color);
        Color decoded = (Color.decode(color));
        return new RGB(decoded.getRed(), decoded.getGreen(), decoded.getBlue());
    }
    public String stringFixer(String s) {
        return "#" + s.charAt(1) + s.charAt(1) + s.charAt(2) + s.charAt(2) + s.charAt(3) + s.charAt(3);
    }
    public String nameFixer(String s) {
        return presetColors.get(s.toLowerCase());
    }
}

Option 2:

import java.util.Map;

class HtmlColorParser {
  private final Map<String, String> presetColors;
  HtmlColorParser(Map<String, String> presetColors) {
    this.presetColors = presetColors;
  }
  RGB parse(String color) {
    if ((color = presetColors.getOrDefault(color.toLowerCase(), color)).length() < 7)
      color = color.replaceAll("((?i)[\\da-f])", "$1$1");
    return new RGB(Integer.valueOf(color.substring(1, 3), 16), Integer.valueOf(color.substring(3, 5), 16), Integer.valueOf(color.substring(5), 16));
  }
}

Option 3:

import java.util.Map;

public class HtmlColorParser {
    private final Map<String, String> presetColors;
    public HtmlColorParser(Map<String, String> presetColors) {
        this.presetColors = presetColors;
    }
    public RGB parse(String color) {
            String lc = color.toLowerCase();
            String rgb = presetColors.getOrDefault(lc, lc);
            if(rgb.length() == 4)
                rgb = rgb.replaceAll("([0-9a-f])", "$1$1");
            return new RGB(Integer.valueOf(rgb.substring(1, 3), 16), 
                           Integer.valueOf(rgb.substring(3, 5), 16),
                           Integer.valueOf(rgb.substring(5), 16));
    }
}

Test cases to validate our solution

import java.util.Locale;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class ExampleTests {
    private HtmlColorParser parser;
    @Before
    public void setup() {
        parser = new HtmlColorParser(PresetColors.getMap());
    }
    @Test
    public void testExamples() {
        shouldParse("#80FFA0", new RGB(128, 255, 160));
        shouldParse("#3B7", new RGB( 51, 187, 119));
        shouldParse("LimeGreen", new RGB( 50, 205,  50));
    }
    private void shouldParse(String color, RGB expected) {
        assertRgbEquals(color, expected, parser.parse(color));
    }
    private static void assertRgbEquals(String input, RGB expected, RGB actual) throws AssertionError {
        try {
            System.out.printf("input: \"%s\"", input);
            assertEquals(expected, actual);
            System.out.println(" => pass!");
        } catch (AssertionError e) {
            String message = String.format(Locale.ENGLISH,
                "expected: %s\nactual  : %s", expected, actual);
            throw new AssertionError(message, e);
        }
    }
}
Tags:
Andrew
Andrew

Andrew is a visionary software engineer and DevOps expert with a proven track record of delivering cutting-edge solutions that drive innovation at Ataiva.com. As a leader on numerous high-profile projects, Andrew brings his exceptional technical expertise and collaborative leadership skills to the table, fostering a culture of agility and excellence within the team. With a passion for architecting scalable systems, automating workflows, and empowering teams, Andrew is a sought-after authority in the field of software development and DevOps.

Tags