1

So i'm parsing a line from text file and getting a string like:

color(black)

or

color(RGB(142,0,0))

So I wrote a code:

private Sprite makeSpriteToBackGround(String line) {
        if (line.contains("color")) {
            ColorsParser colorsParser = new ColorsParser();
            Color color = colorsParser.colorFromString(line.substring(line.indexOf("RGB")));
            return new Sprite() {
                @Override
                public void drawOn(DrawSurface d) {
                    d.setColor(color);
                    d.fillRectangle(0, 0, 800, 600);
                }

                @Override
                public void timePassed() {
                }
            };
}

So my goal is to check whether the line contains "RGB" or not. If it does - it will be parsed through my colorFromString parser function, and if not, it will just will be deployed as the color.

How would you suggest me to parse the

color(black)

part?

because the RGB part works perfectlly.

Dima Ciun
  • 87
  • 1
  • 11

3 Answers3

1

You probably want to check for the presence of RGB first, and then fallback to looking for known values in a lookup table.

Map<String, Color> colors = new HashMap<String, Color>() {{
    put("black", Color.BLACK);
    put("red", Color.RED);
    put("green", Color.GREEN);
    put("blue", Color.BLUE);
}};

Color color = null;
int rgbIndex = line.indexOf("RGB");
if (rgbIndex > -1) {
    color = colorsParser.colorFromString(line.substring(rgbIndex));
} else {
    // There are better ways to extract text between brackets, see https://stackoverflow.com/questions/24256478/pattern-to-extract-text-between-parenthesis/24256532
    String colorName = line.substring(line.indexOf("(") + 1, line.indexOf(")"));
    color = colors.get(colorName);
}

// TODO: Make sure you check if `color` is null here.
DanielGibbs
  • 9,910
  • 11
  • 76
  • 121
  • but there are a lot of colors, I think it wouldn't be efficient to create a map of ALL the colors .. I mean are u suggesting to create a map that contains X colors ? because I need to cover all colors. think about it , you may receive color(black.darker) or something.. – Dima Ciun Jun 24 '20 at 06:36
  • @DimaCiun That’s true. Then you probably want to find a library thst contains the mappings that you want. – DanielGibbs Jun 24 '20 at 08:51
0
public class TestColor {

    public static void main(String[] args) {
        String fullColorStr = "color(yellow)";
        
        //Precondition
        if (fullColorStr == null || fullColorStr.trim().isEmpty()) {
            throw new IllegalArgumentException("Color cannot be empty");
        }
        
        String colorStr = fullColorStr.substring(fullColorStr.indexOf("(")+1,fullColorStr.indexOf(")"));
        Color color = getColorFromString(colorStr);
        System.out.print(color);
    }

    private static Color getColorFromString(String colorStr) {
        //Precondition
        if (colorStr == null || colorStr.trim().isEmpty()) {
            return null;
        }

        Color color = null;
        String lowerColorStr = colorStr.toLowerCase();
        try {
            Field colorField = Color.class.getField(lowerColorStr);
            //Paranoid check start
            Class<?> type = colorField.getType();
            if (type != Color.class) {
                throw new IllegalStateException("Shoudln't have encountered this : " + colorStr);
            } //End 
            color = (Color) colorField.get(Color.class);
        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            throw new IllegalArgumentException("Not a valid color : " + colorStr);
        }
        return color;
    }

}
joy
  • 327
  • 4
  • 11
  • you wrote a code that gets "yellow", but my function receives a string of "color(yellow)" – Dima Ciun Jun 24 '20 at 06:38
  • Getting the text was already mentioned in the previous answer moreover your code suggested you knew how to extract stuff from a String. I wanted to provide you a way without hardcoding the colors. – joy Jun 24 '20 at 06:48
  • I edited my answer to include the line of code to extract "yellow" from "color(yellow)" – joy Jun 24 '20 at 07:11
0

I wonder why none of the other commenters has already mentioned it, but there is an established way to solve this class of problems: Regular Expressions

You described two patterns:

Many deveolpers are afraid of Regular Expressions, but they are extremely helpful here. All you have to do in your code, is to pick the values from the matches:

package color;

import java.awt.Color;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ColorParser {

    private final Pattern namedPattern = Pattern.compile("color\\((\\w+)\\)");
    private final Pattern rgbPattern = Pattern.compile("color\\(RGB\\((\\d+)\\,(\\d+)\\,(\\d+)\\)\\)");

    public Color parse(String line) {
        Color result = parseRGB(line);
        if (result == null) {
            result = parseNamed(line);
        }
        return result;
    }

    private Color parseRGB(String line) {
        final Matcher matcher = rgbPattern.matcher(line);
        if (matcher.find()) {
            final int red = Integer.parseInt(matcher.group(1));
            final int green = Integer.parseInt(matcher.group(2));
            final int blue = Integer.parseInt(matcher.group(3));
            return new Color(red, green, blue);
        }
        return null;
    }

    private Color parseNamed(String line) {
        final Matcher matcher = namedPattern.matcher(line);
        if (matcher.find()) {
            final String name = matcher.group(1);
            try {
                // java.awt.Color is not an enum, so let's use Reflection
                return (Color) Color.class.getField(name.toUpperCase()).get(null);
            } catch (Exception e) {
                // ignore
            }
        }
        return null;
    }
}

Here is a JUnit test to verify it:

package color;

import static org.junit.Assert.assertEquals;

import java.awt.Color;

import org.junit.Test;

public class ColorParserTest {

    final ColorParser sut = new ColorParser();

    @Test
    public void testParse_Named() {
        assertEquals(Color.BLACK, sut.parse("color(black)"));
    }

    @Test
    public void testParse_NamedInText() {
        assertEquals(Color.RED, sut.parse("foo color(Red) bar"));
    }

    @Test
    public void testParse_RGB() {
        assertEquals(Color.ORANGE, sut.parse("color(RGB(255,200,0))"));
    }

    @Test
    public void testParse_Unkown() {
        assertEquals(null, sut.parse("color(foo)"));
    }
}

I used the AWT Color class here. Depending on your use case you might need a mapping table to resolve other named colors, like HTML colors or X11 colors.

oliver_t
  • 968
  • 3
  • 10
  • I think you missed that the first answer had the link to https://stackoverflow.com/questions/24256478/pattern-to-extract-text-between-parenthesis/24256532 which has the Regular expression option. – joy Jun 25 '20 at 23:54