3

次の文字列を指定します。

"foo bar-baz-zzz"

文字 " " と "-" で分割して値を保持したいのですが、入力のすべての組み合わせを取得します。

を含む二次元配列を取得したい

{{"foo", "bar", "baz", "zzz"}
,{"foo bar", "baz", "zzz"}
,{"foo", "bar-baz", "zzz"}
,{"foo bar-baz", "zzz"}
,{"foo", "bar", "baz-zzz"}
,{"foo bar", "baz-zzz"}
,{"foo", "bar-baz-zzz"}
,{"foo bar-baz-zzz"}}

この方法で文字列を分割するための Java の組み込みメソッドはありますか? たぶん、Apache Commons のようなライブラリでしょうか? または、for ループの壁を作成する必要がありますか?

4

5 に答える 5

6

これは機能する再帰的なソリューションですList<List<String>>作業を簡単にするために、2 次元配列ではなく配列を使用しました。コードは少し醜いので、おそらく少し整理することができます。

出力例:

$ java Main foo bar-baz-zzz
Processing: foo bar-baz-zzz
[foo, bar, baz, zzz]
[foo, bar, baz-zzz]
[foo, bar-baz, zzz]
[foo, bar-baz-zzz]
[foo bar, baz, zzz]
[foo bar, baz-zzz]
[foo bar-baz, zzz]
[foo bar-baz-zzz]

コード:

import java.util.*;

public class Main {
  public static void main(String[] args) {
    // First build a single string from the command line args.
    StringBuilder sb = new StringBuilder();
    Iterator<String> it = Arrays.asList(args).iterator();
    while (it.hasNext()) {
      sb.append(it.next());

      if (it.hasNext()) {
        sb.append(' ');
      }
    }

    process(sb.toString());
  }

  protected static void process(String str) {
    System.err.println("Processing: " + str);
    List<List<String>> results = new LinkedList<List<String>>();

    // Invoke the recursive method that does the magic.
    process(str, 0, results, new LinkedList<String>(), new StringBuilder());

    for (List<String> result : results) {
      System.err.println(result);
    }
  }

  protected static void process(String str, int pos, List<List<String>> resultsSoFar, List<String> currentResult, StringBuilder sb) {
    if (pos == str.length()) {
      // Base case: Reached end of string so add buffer contents to current result
      // and add current result to resultsSoFar.
      currentResult.add(sb.toString());
      resultsSoFar.add(currentResult);
    } else {
      // Step case: Inspect character at pos and then make recursive call.
      char c = str.charAt(pos);

      if (c == ' ' || c == '-') {
        // When we encounter a ' ' or '-' we recurse twice; once where we treat
        // the character as a delimiter and once where we treat it as a 'normal'
        // character.
        List<String> copy = new LinkedList<String>(currentResult);
        copy.add(sb.toString());
        process(str, pos + 1, resultsSoFar, copy, new StringBuilder());

        sb.append(c);
        process(str, pos + 1, resultsSoFar, currentResult, sb);
      } else {
        sb.append(c);
        process(str, pos + 1, resultsSoFar, currentResult, sb);
      }
    }
  }
}
于 2009-08-25T15:40:24.807 に答える
3

分割された値のリストを遅延して返すクラスを次に示します。

public class Split implements Iterator<List<String>> {
  private Split kid;                 private final Pattern pattern;
  private String subsequence;        private final Matcher matcher;
  private boolean done = false;      private final String sequence;
  public Split(Pattern pattern, String sequence) {
    this.pattern = pattern;          matcher = pattern.matcher(sequence);
    this.sequence = sequence;
  }

  @Override public List<String> next() {
    if (done) { throw new IllegalStateException(); }
    while (true) {
      if (kid == null) {
        if (matcher.find()) {
          subsequence = sequence.substring(matcher.end());
          kid = new Split(pattern, sequence.substring(0, matcher.start()));
        } else { break; }
      } else {
        if (kid.hasNext()) {
          List<String> next = kid.next();
          next.add(subsequence);
          return next;
        } else { kid = null; }
      }
    }
    done = true;
    List<String> list = new ArrayList<String>();
    list.add(sequence);
    return list;
  }
  @Override public boolean hasNext() { return !done; }
  @Override public void remove() { throw new UnsupportedOperationException(); }
}

(コードのフォーマットを許してください - ネストされたスクロールバーを避けるためです)。

サンプル呼び出しの場合:

Pattern pattern = Pattern.compile(" |-");
String str = "foo bar-baz-zzz";
Split split = new Split(pattern, str);
while (split.hasNext()) {
  System.out.println(split.next());
}

...それは放出します:

[foo, bar-baz-zzz]
[foo, bar, baz-zzz]
[foo bar, baz-zzz]
[foo, bar-baz, zzz]
[foo, bar, baz, zzz]
[foo bar, baz, zzz]
[foo bar-baz, zzz]
[foo bar-baz-zzz]

実装が改善される可能性があると思います。

于 2009-08-25T16:43:48.720 に答える
1

なぜそれが必要なのですか?

N トークンの特定の文字列に対して、約 N*2^N 文字列の配列を取得することに注意してください。安全な方法で行わないと、大量のメモリを消費する可能性があります...

おそらく、すべてを繰り返す必要があると思いますよね?その場合は、元の文字列を保持し、要求するたびに行を分割するさまざまな方法を提供するクラスを作成することをお勧めします。このようにして、大量のメモリを節約し、スケーラビリティを向上させます。

于 2009-08-25T16:26:30.313 に答える
0

ライブラリメソッドはありません。

それを達成するには、区切り記号を保持して文字列をトークン化する必要があります (この場合は "-" を使用)。次に、区切り記号をバイナリ フラグに関連付けられていると考え、フラグの値に基づいてすべての組み合わせを作成する必要があります。

あなたの場合、" "、"-"、"-" の 3 つの区切り記号があるため、3 つのバイナリ フラグがあります。文字列には 2^3 = 8 個の値が含まれます。

于 2009-08-25T15:40:18.520 に答える