views:

51

answers:

4

This is my class Debugger. Can anyone try and run it and see whens wrong? Ive spent hours on it already. :(

public class Debugger {

private String codeToDebug = "";

public Debugger(String code) {
    codeToDebug = code;
}

/**
 * This method itterates over a css file and adds all the properties to an arraylist
 */
public void searchDuplicates() {
    boolean isInside = false;
    ArrayList<String> methodStorage = new ArrayList();
    int stored = 0;
    String[] codeArray = codeToDebug.split("");

    try {
        int i = 0;
        while(i<codeArray.length) {
            if(codeArray[i].equals("}")) {
                isInside = false;
            }
            if(isInside && !codeArray[i].equals(" ")) {
                boolean methodFound = false;
                String method = "";
                int c = i;
                while(!methodFound) {
                    method += codeArray[c];
                    if(codeArray[c+1].equals(":")) {
                        methodFound = true;
                    } else {
                        c++;
                    }
                }
                methodStorage.add(stored, method);

                System.out.println(methodStorage.get(stored));
                stored++;

                boolean stillInside = true;
                int skip = i;
                while(stillInside) {
                    if(codeArray[skip].equals(";")) {
                        stillInside = false;
                    } else {
                        skip++;
                    }
                }
                i = skip;
            }
            if(codeArray[i].equals("{")) {
                isInside = true;
            }
            i++;
        }
    } catch(ArrayIndexOutOfBoundsException ar) {
        System.out.println("------- array out of bounds exception -------");
    }
}

/**
 * Takes in String and outputs the number of characters it contains
 * @param input
 * @return Number of characters
 */
public static int countString(String input) {
    String[] words = input.split("");
    int counter = -1;
    for(int i = 0; i<words.length; i++){
        counter++;
    }
    return counter;
}

public static void main(String[] args) {
    Debugger h = new Debugger("body {margin:;\n}");
    h.searchDuplicates();
}

}

+1  A: 

Any place where an element of an array is being obtained without a bounds check after the index is manipulated is an candidate for an ArrayIndexOutOfBoundsException.

In the above code, there are at least two instances where the index is being manipulated without being subject to a bounds check.

  1. The while loop checking the !methodFound condition
  2. The while loop checking the stillInside condition

In those two cases, the index is being manipulated by incrementing or adding a value to the index, but there are no bound checks before an element is being obtained from the String[], therefore there is no guarantee that the index being specified is not outside the bounds of the array.

coobird
A: 

I think this block of codes can create your problem

int c = i;
while(!methodFound) {
    method += codeArray[c];
    if(codeArray[c+1].equals(":")) {
         methodFound = true;
    } else {
         c++;
    }
}


int skip = i;
while(stillInside) {
    if(codeArray[skip].equals(";")) {
       stillInside = false;
    } else {
       skip++;
    }
 }
 i = skip;

The reason is that if the condition is true, and i = codeArray.length - 1. The c + 1 will create the error of ArrayIndexOutOfBound

vodkhang
A: 

Try evaluating if your index exists in the array...

adding:

while (!methodFound && c < codeArray.length) {

while (stillInside && skip < codeArray.length) {

if (i < codeArray.length && codeArray[i].equals("{")) {

so, your code looks like:

public class Debugger {

    private String codeToDebug = "";

    public Debugger(String code) {
        codeToDebug = code;
    }

    /**
     * This method itterates over a css file and adds all the properties to an
     * arraylist
     */
    public void searchDuplicates() {
        boolean isInside = false;
        List<String> methodStorage = new ArrayList<String>();
        int stored = 0;
        String[] codeArray = codeToDebug.split("");

        try {
            int i = 0;
            while (i < codeArray.length) {
                if (codeArray[i].equals("}")) {
                    isInside = false;
                }
                if (isInside && !codeArray[i].equals(" ")) {
                    boolean methodFound = false;
                    String method = "";
                    int c = i;
                    while (!methodFound && c < codeArray.length) {
                        method += codeArray[c];
                        if (codeArray[c].equals(":")) {
                            methodFound = true;
                        } else {
                            c++;
                        }
                    }
                    methodStorage.add(stored, method);

                    System.out.println(methodStorage.get(stored));
                    stored++;

                    boolean stillInside = true;
                    int skip = i;
                    while (stillInside && skip < codeArray.length) {
                        if (codeArray[skip].equals(";")) {
                            stillInside = false;
                        } else {
                            skip++;
                        }
                    }
                    i = skip;
                }
                if (i < codeArray.length && codeArray[i].equals("{")) {
                    isInside = true;
                }
                i++;
            }
        } catch (ArrayIndexOutOfBoundsException ar) {
            System.out.println("------- array out of bounds exception -------");
            ar.printStackTrace();
        }
    }

    /**
     * Takes in String and outputs the number of characters it contains
     * 
     * @param input
     * @return Number of characters
     */
    public static int countString(String input) {
        String[] words = input.split("");
        int counter = -1;
        for (int i = 0; i < words.length; i++) {
            counter++;
        }
        return counter;
    }

    public static void main(String[] args) {
        Debugger h = new Debugger("body {margin:prueba;\n}");
        h.searchDuplicates();
    }
}

Also, declaring implementation types is a bad practice, because of that in the above code i Change the ArrayList variable = new ArrayList() to List variable = new ArrayList()

Garis Suero
This still throws the exception... Also, I have noticed that it only throws it if it iterates over a "\n"
Jacob
forgot to remove the 'c + 1' from the code... to be only c...
Garis Suero
A: 

I couldn't resist to implement this task of writing a CSS parser in a completely different way. I have split the task of parsing into many small ones.

  • The smallest is called skipWhitespace, since you will need it everywhere when parsing text files.
  • The next one is parseProperty, which reads one property of the form name:value;.
  • Based on that, parseSelector reads a complete CSS selector, starting with the selector name, an opening brace, possibly many properties, and finishing with the closing brace.
  • Still based on that, parseFile reads a complete file, consisting of possibly many selectors.

Note how carefully I checked whether the index is small enough. I did that before every access to the chars array.

I used LinkedHashMaps to save the properties and the selectors, because these kinds of maps remember in which order the things have been inserted. Normal HashMaps don't do that.

The task of parsing a text file is generally quite complex, and this program only attempts to handle the basics of CSS. If you need a full CSS parser, you should definitely look for a ready-made one. This one cannot handle @media or similar things where you have nested blocks. But it shouldn't bee too difficult to add it to the existing code.

This parser will not handle CSS comments very well. It only expects them at a few places. If comments appear in other places, the parser will not treat them as comments.

import java.util.LinkedHashMap;
import java.util.Map;

public class CssParser {

  private final char[] chars;
  private int index;

  public Debugger(String code) {
    this.chars = code.toCharArray();
    this.index = 0;
  }

  private void skipWhitespace() {
    /*
     * Here you should also skip comments in the CSS file, which either look
     * like this comment or start with a // and go until the end of line.
     */
    while (index < chars.length && Character.isWhitespace(chars[index]))
      index++;
  }

  private void parseProperty(String selector, Map<String, String> properties) {
    skipWhitespace();

    // get the CSS property name
    StringBuilder sb = new StringBuilder();
    while (index < chars.length && chars[index] != ':')
      sb.append(chars[index++]);
    String propertyName = sb.toString().trim();

    if (index == chars.length)
      throw new IllegalArgumentException("Expected a colon at index " + index + ".");

    // skip the colon
    index++;

    // get the CSS property value
    sb.setLength(0);
    while (index < chars.length && chars[index] != ';' && chars[index] != '}')
      sb.append(chars[index++]);
    String propertyValue = sb.toString().trim();

    /*
     * Here is the check for duplicate property definitions. The method
     * Map.put(Object, Object) always returns the value that had been stored
     * under the given name before.
     */
    String previousValue = properties.put(propertyName, propertyValue);
    if (previousValue != null)
      throw new IllegalArgumentException("Duplicate property \"" + propertyName + "\" in selector \"" + selector + "\".");

    if (index < chars.length && chars[index] == ';')
      index++;
    skipWhitespace();
  }

  private void parseSelector(Map<String, Map<String, String>> selectors) {
    skipWhitespace();

    // get the CSS selector
    StringBuilder sb = new StringBuilder();
    while (index < chars.length && chars[index] != '{')
      sb.append(chars[index++]);
    String selector = sb.toString().trim();

    if (index == chars.length)
      throw new IllegalArgumentException("CSS Selector name \"" + selector + "\" without content.");

    // skip the opening brace
    index++;
    skipWhitespace();

    Map<String, String> properties = new LinkedHashMap<String, String>();
    selectors.put(selector, properties);

    while (index < chars.length && chars[index] != '}') {
      parseProperty(selector, properties);
      skipWhitespace();
    }

    // skip the closing brace
    index++;
  }

  private Map<String, Map<String, String>> parseFile() {
    Map<String, Map<String, String>> selectors = new LinkedHashMap<String, Map<String, String>>();
    while (index < chars.length) {
      parseSelector(selectors);
      skipWhitespace();
    }
    return selectors;
  }

  public static void main(String[] args) {
    CssParser parser = new CssParser("body {margin:prueba;A:B;a:Arial, Courier New, \"monospace\";\n}");
    Map<String, Map<String, String>> selectors = parser.parseFile();

    System.out.println("There are " + selectors.size() + " selectors.");
    for (Map.Entry<String, Map<String, String>> entry : selectors.entrySet()) {
      String selector = entry.getKey();
      Map<String, String> properties = entry.getValue();

      System.out.println("Selector " + selector + ":");

      for (Map.Entry<String, String> property : properties.entrySet()) {
        String name = property.getKey();
        String value = property.getValue();
        System.out.println("  Property name \"" + name + "\" value \"" + value + "\"");
      }
    }
  }
}
Roland Illig