3

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

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

我需要把它分成

苹果
男生
猫
狗猫
中午之后的时间

我尝试使用

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

第二部分,但我无法得到正确的答案,你能帮我吗?

4

3 回答 3

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:已修复。应该像现在宣传的那样工作。还对其进行了修改以测试行号和列号的跟踪。

于 2013-03-02T22:40:32.093 回答
0

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

编辑:我不确定这是否可以用 String.split() 来完成。我认为在只匹配逗号的同时处理引号的唯一方法是预读和后视,这在很多情况下都会中断。

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());
}

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

但后来我想我快到了。它吐出来了……哦,嘿,我明白这里发生了什么。我想我可以解决这个问题。

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

于 2013-03-02T21:43:46.467 回答
0

我不太确定,但你可以试试Pattern.compile("[\\\\"]");

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

另一种情况下,类似的事情对我有用,我希望它也能解决你的问题。

于 2013-03-02T23:07:43.167 回答