Java使用对象来保持状态似乎并不起作用

时间:2014-05-04 23:15:54

标签: java oop

我正在编写一个应该能够解析分隔文件(逗号,管道,冒号分隔)的实用程序类。它读取特定行并需要提取该行中最常用的分隔符。但这似乎没有按预期工作。当我在main方法调用者类中调用getHeader()方法时,似乎唯一被确认的分隔符是来自该行的逗号。我认为我的弱java和oop缺乏技能阻止我理解这个问题。请指教。先感谢您。以下是我的代码:

    public class Parser {
    // sample line of data
    String line = "There|is|data,in,this:file|hause";

    private static class Delimiters {
        static char DEFAULT = ',';
        static char COMMA = ',';
        static char SEMI = ';';
        static char PIPE = '|';
        static char COLON = ':';
    };

    public String[] getHeader() {
        char delim = findDelimiter(line);
        System.out.println("Header delim: " + delim);
        String[] columns = line.split(String.valueOf(delim));
        return columns;
    }

    // figure out the delimiter of the file. This method
    // gets called on lines of file data
    public char findDelimiter(String line) {
        Delimiter dim = new Delimiter();
        for (int i = 0; i < line.length(); i++) {
            for (char delim : Arrays.asList(Delimiters.COLON, Delimiters.COMMA,
                    Delimiters.PIPE, Delimiters.SEMI)) {
                if (delim == line.charAt(i)) {
                    dim.increaseDelimiterCnt(delim);
                }
            }
        }

        final char theLinesDelimiter = dim.mostCommonDelimiter();
        return theLinesDelimiter;
    }

    private class Delimiter {
        Map<Character, Integer> delimiterCounts = new HashMap<Character, Integer>();

        private void increaseDelimiterCnt(char delim) {
            System.out.println(delim);

            int value = (delimiterCounts.containsKey(delim) ? delimiterCounts
                    .get(delim) : 0);
            delimiterCounts.put(delim, value++);
            System.out.println(getDelimiterCounts());
        }

        private Map<Character, Integer> getDelimiterCounts() {
            return delimiterCounts;
        }

        /**
         * Gets the delimiter based on greatest frequency of first line in file.
         * 
         * @return String
         */
        private char mostCommonDelimiter() {
            char theDelimiter = ',';
            System.out.println(delimiterCounts);
            int maxValueInMap = (Collections.max(delimiterCounts.values()));
            for (Map.Entry<Character, Integer> entry : delimiterCounts
                    .entrySet()) {
                if (entry.getValue().equals(maxValueInMap)) {
                    theDelimiter = entry.getKey();
                }
            }
            return theDelimiter;
        }
    }

}

3 个答案:

答案 0 :(得分:2)

错误就在这一行:

            delimiterCounts.put(delim, value++);
变量名后面的

++帖子 - 增量,所以虽然value++增加了value,但仍然评估到原来的价值。所以,上述内容相当于:

            delimiterCounts.put(delim, value);
            value = value + 1; // pointless, since we never use value again

相反,你应该写:

            delimiterCounts.put(delim, value + 1);

你的调试输出实际上已经足够告诉你了;它向您显示delimiterCounts中的每个分隔符都映射到零。

我建议你阅读Eric Lippert's blog post, "How to debug small programs"。您可能会发现它对未来很有用。

(注意:在解决上述问题之后,您还会遇到另一个问题。您的程序现在会正确识别|作为分隔符,但line.split("|")并不代表您想要的内容。一,你要使用Pattern.quote。我会让你弄清楚细节。)


编辑添加:由于您对OOP有疑虑,我还应该谈谈整体设计。您可以使用枚举创建更强大,更高效的设计:

public enum Delimiter {
    COMMA(','), SEMI(';'), PIPE('|'), COLON(':');

    public final char c;
    public final Pattern pattern;

    private DelimiterChar(final char c) {
        this.c = c;
        this.pattern = Pattern.compile(Pattern.quote(Character.toString(c)));
    }
}

然后,当您需要枚举可能的分隔符时,可以使用Delimiter.values(),并且可以使用EnumSet<Delimiter, Integer>来按分隔符存储计数。

请注意,我使用名称Delimiter来表示与您有所不同的名称。您的Delimiter类可能应该被称为DelimiterCounter,因为它的实例会计算分隔符,而不是自己分隔任何内容。

答案 1 :(得分:1)

您的findDelmiter方法已损坏。而且,这都是一个角色的错。

String#split将其参数解析为正则表达式。管道特征在正则表达式中具有特殊含义;也就是说,它用于表示分支匹配。

如果要使用文字管道,则必须将其转义。您不能在单个字符文字中执行此操作(因为转义仅具有String的上下文含义,而不是char

为什么不完全使用正则表达式进行拆分方法?我们不用担心选择我们使用哪一个那里,当我们可以重建时,如果需要的话。

这是一个片段。

String[] columns = line.split(",|;|\\||:");

复杂外观的正则表达式实际上是使用管道字符进行分支 - 它将分为逗号,分号,管道(正确转义)或冒号。

我很钦佩你正在使用帮助程序类来确定分隔符的数量。但是,您需要注意插入地图的方式 - 确保密钥首先存在,如果确实,请将当前值拉出,并向其中添加一个,然后把它放回去。

这是一个片段。

private static void placeIntoMap(final Map<Character, Integer> counts, final char c) {
    if(counts.containsKey(c)) {
        counts.put(c, counts.get(c) + 1);
    } else {
        counts.put(c, 1);
    }
}

答案 2 :(得分:0)

您可以使用split来计算您获得的字符串数量。只需减去1,因为除法器的数量总是比零件数少1。

public class Parser {

    static String line = "There|is|data,in,this:file|hause";
    private static final String[] DELIMS = {",", ";", "\\|", ":"};
    private static Map<String, Integer> count = new HashMap<>();

    public static void main(String[] args) {

        for (String delim : DELIMS)
            count.put(DELIMS[i], line.split(DELIMS[i]).length - 1);
    }
}