我正在编写一个应该能够解析分隔文件(逗号,管道,冒号分隔)的实用程序类。它读取特定行并需要提取该行中最常用的分隔符。但这似乎没有按预期工作。当我在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;
}
}
}
答案 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);
}
}