java中的正则表达式

时间:2013-03-02 21:39:00

标签: java regex parsing csv pattern-matching

我需要为从文件中读取的字符串写一个正则表达式

apple,boy,cat,"dog,cat","time\" after\"noon"

我需要将其拆分为

apple
boy
cat
dog,cat
time"after"noon

我尝试使用

Pattern pattern = 
Pattern.compile("[\\\"]");
String items[]=pattern.split(match);

对于第二部分,但我无法得到正确答案,你能帮我解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

由于您的问题更多的是解析问题而不是正则表达式问题,因此这是另一个可行的解决方案:

public class CsvReader {

    Reader r;
    int row, col;
    boolean endOfRow;

    public CsvReader(Reader r){
        this.r = r instanceof BufferedReader ? r : new BufferedReader(r);
        this.row = -1;
        this.col = 0;
        this.endOfRow = true;
    }

    /**
     * Returns the next string in the input stream, or null when no input is left
     * @return
     * @throws IOException  
     */
    public String next() throws IOException {
        int i = r.read();
        if(i == -1)
            return null;

        if(this.endOfRow){
            this.row++;
            this.col = 0;
            this.endOfRow = false;
        } else {
            this.col++;
        }

        StringBuilder b = new StringBuilder();
outerLoop:  
        while(true){
            char c = (char) i;
            if(i == -1)
                break;
            if(c == ','){
                break;
            } else if(c == '\n'){
                endOfRow = true;
                break;
            } else if(c == '\\'){
                i = r.read();
                if(i == -1){
                    break;
                } else {
                    b.append((char)i);
                }
            } else if(c == '"'){
                while(true){
                    i = r.read();

                    if(i == -1){
                        break outerLoop;
                    }
                    c = (char)i;
                    if(c == '\\'){
                        i = r.read();
                        if(i == -1){
                            break outerLoop;
                        } else {
                            b.append((char)i);
                        }
                    } else if(c == '"'){
                        r.mark(2);
                        i = r.read();
                        if(i == '"'){
                            b.append('"');
                        } else {
                            r.reset();
                            break;
                        }
                    } else {
                        b.append(c);
                    }
                }
            } else {
                b.append(c);
            }
            i = r.read();
        }

        return b.toString().trim();
    }


    public int getColNum(){
        return col;
    }

    public int getRowNum(){
        return row;
    }

    public static void main(String[] args){

        try {
            String input = "apple,boy,cat,\"dog,cat\",\"time\\\" after\\\"noon\"\nquick\"fix\" hello, \"\"\"who's there?\"";
            System.out.println(input);
            Reader r = new StringReader(input);
            CsvReader csv = new CsvReader(r);
            String s;
            while((s = csv.next()) != null){
                System.out.println("R" + csv.getRowNum() + "C" + csv.getColNum() + ": " + s);
            }
        } catch(IOException e){
            e.printStackTrace();
        }
    }
}

运行此代码,我得到输出:

R0C0: apple
R0C1: boy
R0C2: cat
R0C3: dog,cat
R0C4: time" after"noon
R1C0: quickfix hello
R1C1: "who's there?

这应该很适合你的需求。

但有一些免责声明:

  • 它不会捕获CSV格式语法中的错误,例如值中间的未转义引号。
  • 它不会执行任何字符转换(例如将“\ n”转换为换行符)。反斜杠只会导致以下字符被字面处理,包括其他反斜杠。 (如果您需要其他功能,这应该很容易改变)
  • 有些csv文件通过将它们加倍而不是使用反斜杠来转义引号,此代码现在查找两者。

编辑:查看csv格式,发现没有真正的标准,但更新了我的代码以捕获通过加倍而不是反斜杠转义的引号。

编辑2:已修复。应该像现在广告一样工作。还修改了它以测试行号和列号的跟踪。

答案 1 :(得分:0)

首先:String.split()使用正则表达式来查找分隔符,而不是子字符串。

编辑:我不确定是否可以使用String.split()完成此操作。我认为只有匹配逗号才能处理引号的唯一方法是通过readahead和lookbehind,并且在很多情况下都会破坏。

Edit2:我很确定它可以用正则表达式完成。我确信这一个案例可以通过string.split()来解决 - 但一般解决方案并不简单。

基本上,你正在寻找任何不是逗号作为输入[^,]的东西,你可以将引号作为单独的字符处理。我自己已经完成了大部分工作。我得到这个作为输出:

apple

boy

cat


dog

cat



time\" after\"noon

但我不确定为什么会有这么多空白。

我的完整代码是:

String input = "apple,boy,cat,\"dog,cat\",\"time\\\" after\\\"noon\"";

Pattern pattern =
        Pattern.compile("(\\s|[^,\"\\\\]|(\\\\.)||(\".*\"))*");
Matcher m = pattern.matcher(input);

while(m.find()){
    System.out.println(m.group());
}

但是,是的,我会回应上面的那个人并说如果没有要求使用正则表达式,那么手动执行它可能更简单。

但是我想我差不多了。它吐出来......哦,嘿,我看到这里发生了什么。我想我可以解决这个问题。

但是我要回应上面的那个人并说如果不需要使用正则表达式,那么最好一次做一个字符并手动实现逻辑。如果你的正则表达式不完美,那么它可能会造成各种不可预测的怪异。

答案 2 :(得分:0)

我对此并不十分确定,但你可以去 Pattern.compile("[\\\\"]");

\是一个转义字符,要检测表达式中的\,可以使用\\\\

类似的事情在another context中对我有用,我希望它也能解决你的问题。