0

このリンクhttp://osherove.com/tdd-kata-1/からテスト駆動開発の次の演習を解決しようとしていますが、要件の終わり近くで立ち往生しています。

私はいつも正規表現を恐れていましたが、それを学ばなければならないようです。とにかく、私は次のことをしようとしています: - 文字列を取り、そこから数値を抽出して合計します。私を悩ませている要件は、

次のような複数の区切り文字を許可します: 「//[delim1][delim2]\n」、たとえば「//[*][%]\n1*2%3」は 6 を返す必要があります。長さのある複数の区切り文字も処理できることを確認してください。 1 文字より長い。

この要件は、改行記号で始まり改行記号で終わる文字列から 、 などdelim1を抽出する必要があることを意味します。次に、これらの区切り記号を使用して、 の後の数字を抽出する必要があります。各区切り文字は角括弧で囲まれています。delim2//\n\n

さて、正規表現を使用してJavaでそれを行うにはどうすればよいですか?

私が今まで持っているのは、上記のリンクの要件をカバーする次のコードです。

import java.util.ArrayList;

public class Calculator {

    public String getDelimiter(String input) {
        String delimiter = "";
        String changeDelimiter = input.split("\\n")[0];
        delimiter = changeDelimiter.substring(2);
        return delimiter;
    }

    public int calculate(String input) {
        String[] numbers;

        if (input.contains("//")) {
            String delimiter = getDelimiter(input);
            System.out.println("aaaaaaaaaaaaaaaaaaaaaaa : " + delimiter); //testing the value
            String calculation = input.split("\\n")[1];
            numbers = calculation.split("[" + delimiter + "]+");
            System.out.println("bbbbbbbbbbbbbbbbbbbbbbbb"); //testing the values
            for (String number : numbers) {
                System.out.print(number + ":");
                // System.out.print(Integer.parseInt(number) + " ");
            }

        } else
            numbers = input.split(",|\\n");

        if (input.isEmpty()) {
            return 0;
        }
        if (input.length() == 1) {
            return Integer.parseInt(input);
        }
        else {
            return getSum(numbers);
        }
    }

    private int getSum(String[] numbers) throws IllegalArgumentException {
        int sum = 0;
        ArrayList<Integer> negatives = new ArrayList<Integer>();
        for (int i = 0; i < numbers.length; i++) {
            if (Integer.parseInt(numbers[i]) < 0) {
                negatives.add(Integer.parseInt(numbers[i]));
            }
            if (Integer.parseInt(numbers[i]) >= 1000) {
                continue;
            } else
                sum += Integer.parseInt(numbers[i]);
        }
        if (negatives.isEmpty()) {
            return sum;
        } else {
            String negativeNumbers = "";
            for (Integer number : negatives) {
                negativeNumbers += number.toString() + " ";
            }
            throw new IllegalArgumentException("Negatives not allowed : " + negativeNumbers);
        }

    }

}
4

2 に答える 2

0

これは、任意の数字に一致するだけではありませんが、「delim1」のような区切り文字、つまり数字を含む区切り文字に対して機能するはずです。パターンと手順をインラインで説明しようとしました。

    final String input = "//[delim1][delim2]\n12delim125delim2";
    // split the input string so you will get anything after // and before \n
    // and anything after \n until end of line ($)
    Pattern p = Pattern.compile("^//(.+)\\n(.*)$");
    Matcher m = p.matcher(input);
    if (!m.matches()) {
      System.out.println("Input string not valid");
      return;
    }

    String delimString = m.group(1);
    String searchString = m.group(2);

    // This matches the opening square bracket,
    // then as a capturing group, anything except a closing bracket. 
    // Finally it matches the closing bracket of the delimiter definition.
    Pattern pDelim = Pattern.compile("\\[([^\\]]+)\\]");
    Matcher mDelim = pDelim.matcher(delimString);

    // build a regex for String.split in the format: delim1|delim2|delim3|...
    String delimiters = "";
    while (mDelim.find()) {
     delimiters += (Pattern.quote(mDelim.group(1)) + "|");
    }
    delimiters = delimiters.substring(0, delimiters.length()-1);

    // split string and convert numbers to integers, then sum them up
    String[] numStrings = searchString.split(delimiters);
    int sum = 0;
    for (String num : numStrings) {
      sum += Integer.parseInt(num);
    }

    System.out.println("Sum: " + sum);

編集/もう少し説明

正規表現には、次の\\[([^\\]]+)\\]3 つの部分が含まれます。

  • "\\[": これは区切り文字定義の左角括弧と一致します。2 つのバックスラッシュが必要であることに注意してください。1 つが Java コンパイラによって解釈されるためです。[ただし、正規表現の特殊文字も一致させたいと考えています。したがって、2つ必要です。
  • ([^\\]]+): 外側の括弧は、いわゆるキャプチャ グループを作成します。グループのインデックスであるMatcher.group(n)whereを使用して後でアクセスできます。nしたがって、1 は定義された最初のグループ、2 は 2 番目のグループ、というようになります。0 は一致する文字列全体を返します。

    • [^\\]]+: この正規表現は、区切り文字定義の内容、つまり角括弧内のすべてと一致します。今回は、アウター[]は抜けていません。それらは特別な意味を持ち、文字クラスを定義します。文字クラスは、その中に指定された任意の文字と一致します。たとえば、orまたは[abc]には一致しますが、 には一致しません。文字クラスの先頭には特別な意味があり、文字クラスを反転します。したがって、[^abc] は , または を除く任意の文字に一致しますabcd^abc

      文字クラスで定義されている唯一の文字は]であるため、文字クラスは、区切り記号の定義を終了する閉じ角括弧を除くすべての文字と一致します。文字クラスへの+追加は、少なくとも 1 文字、可能であればそれ以上の文字に一致することを意味します。

  • \\]: 閉じ角かっこを一致させるだけです。

この正規表現では、 and を呼び出して区切り文字列を受け取りMatcher.find()ますMatcher.group(1)String.split()区切り文字パラメーターにも正規表現を使用します。そのため、以前に解析した任意の区切り文字列に一致する正規表現を作成する必要があります。Pattern.quote()区切り文字列をエスケープするために使用されます。これは、正規表現によって解釈される特殊文字が区切り文字に含まれている場合に必要になることがあります。|であるような特殊文字ですor。構築する正規表現文字列全体は、任意の区切り文字列と一致します。したがってString.split()、区切り文字で文字列を分割します。

于 2013-07-03T14:45:11.863 に答える
0

正規表現を使用できます

\d1桁に一致

+先行するパターン 1 から何度も一致する量指定子です

したがって\d+、1から複数の数字に一致します


あなたのコードは

public int addAllInts(String s)
{
    int temp=0;
    Matcher m=Pattern.compile("\\d+").matcher();
    while(m.find())
    {
        temp+=Integer.parseInt(m.group());
    }
    return temp;
}
于 2013-07-03T14:13:32.307 に答える