0

パイプで区切られたパラメーターを受け取り、それをトークン化する必要があります。ただし、パイプは \| でエスケープできます。セパレータではなく、トークンの一部であることを示します。Java コンパイラーは、文字列リテラルに " およびエスケープされた引用符 \" がある文字列でこれを行うことを知っています。

しかし、そのような文字列をトークン化するための優れたユーティリティ関数/アルゴリズムはわかりません。出力は文字列のリストになります。

サンプル入力 1: "jk|g4"、出力 : "jk" , "g4"(2 つの文字列を含むリスト)

サンプル入力 2: "j\|k|g4|b"、出力 : "j|k" , "g4", "b"(3 つの文字列とリテラル パイプを含むリスト)

を使用してみString.indexOf("|")ましたが、前の文字が \ ... であるかどうかを確認しましたが、エラーがあり、確認したかったのです : もっと簡単な方法はありますか? 正規表現?

これが私が持っているものです:

import java.util.ArrayList;
import java.util.List;

public class PasrePipes {
    public static void main(String[] args) {

        String in = "j\\|k|g4|b";
        {
            String[] ex = { "j|k", "g4", "b" };
            tst(in, ex);
        }

        in = "j|k|g4|b";
        {
            String[] ex = { "j", "k", "g4", "b" };
            tst(in, ex);
        }
    }

    private static void tst(String in, String[] ex) {
        System.out.println("----\n" + in);
        List<String> toks = parse(in);
        if (toks.size() != ex.length) {
            System.out.println("size mismatch, got :" + toks.size() + " exp " + ex.length);
        }
        for (int i = 0; i < ex.length; i++) {
            if (toks.size() > i) {
                String n = toks.get(i);
                if (!ex[i].equals(n)) {
                    System.out.println(" mismatch :" + i + ", got :" + n + "; exp :" + ex[i]);
                } else {
                    System.out.println(" okay :" + i + "; exp :" + ex[i]);
                }
            }
        }

        System.out.println("--");
    }

    private static List<String> parse(String in) {
        List<String> tokens = new ArrayList<String>();
        int i = in.indexOf('|');
        int old = 0;

        while (i > -1) {
            if (i > 0) {
                if (in.charAt(i - 1) == '\\') {
                    i = in.indexOf('|', i + 1);
                    continue;
                }
            }
            String s = in.substring(old, i);
            s.replace("\\|", "|");
            tokens.add(s);
            old = i + 1;
            i = in.indexOf('|', i + 1);

        }
        if(i > 0 && i < (in.length() - 1)) {
            String s = in.substring(i + 1);
            s.replace("\\|", "|");
            tokens.add(s);
        }
        return tokens;

    }
}
4

3 に答える 3

4

単一の正規表現ステートメントで分割と置換の両方を行う方法はありません。ただし、否定的な後ろ向きを使用して分割できます。

(?<!\\)[\|]

そして\||

String value = "j\\|k|g4|b";
String[] split = value.split("(?<!\\\\)(\\|)");
for(int i = 0; i < split.length; i++){
    split[i] = split[i].replaceAll("(\\\\\\|)", "\\|");
    System.out.println(split[i]);
}

出力:

j|k
g4
b

アップデート

ただし、パイプの直前でスラッシュをエスケープしている場合、これは機能しないことに注意してください。

String value = "j\\\\|k|g4|b";
...

出力:

j\|k
g4
b

望ましい出力:

j\
k
g4
b

Java は可変長の後読みをサポートしていないため、区切り文字で文字列を分割する方法はありません。ただし、PatternandMatcherを使用して、区切り文字の前に偶数個のスラッシュがあるすべてのフィールドと照合することができます。

String value = "j\\|k|g4|b|kjbk\\\\\\|\\ml|jbkjbjk\\\\\\\\|k\\jb\\k\\\\\\j|m\\\\\\|\\\\kb";
Pattern pattern = Pattern.compile("(([^\\\\](\\\\\\\\)*\\\\\\|)|([^\\|]))+");
Matcher matcher = pattern.matcher(value);
List<String> fields = new ArrayList<String>();
while(matcher.find()){
    String field = matcher.group().replaceAll("(\\\\\\|)", "\\|");
    fields.add(field);
    System.out.println(field);
}

出力:

j|k
g4
b
kjbk\\|\ml
jbkjbjk\\\\
k\jb\k\\\j
m\\|\\kb
于 2013-08-26T16:55:15.327 に答える
2

これは (Syon が示したように) 正規表現で行うことができますが、複雑すぎてエラーが発生しやすいようです。私はこの単純な関数がはるかに優れた解決策だと思います:

/*
 * Parses a delimited string with an escape character 
 */
public static List<String> parse(String s, char delimeter, char escape){
    List<String> result = new ArrayList<String>();

    StringBuilder sb = new StringBuilder();
    boolean escaped = false;
    for(char ch : s.toCharArray()){
        if(escaped){ 
            sb.append(ch);
            escaped = false;
        }
        else {
            if (ch == escape){
                escaped = true;
            }
            else if(ch == delimeter){
                result.add(sb.toString());
                sb.setLength(0);
            }
            else{
                sb.append(ch);
            }
        }
    }

    result.add(sb.toString());

    return result;
}

次のように呼び出します。

parse("j\\|k|g4|b", '|', '\\')    // --> [ "j|k", "g4", "b" ]
于 2014-05-06T01:13:03.593 に答える