2013-07-03 3 views
0

Я пытаюсь решить следующее упражнение для разработки, основанной на тестах, по этой ссылке http://osherove.com/tdd-kata-1/, и я застрял чуть ближе к концу требований.Как извлечь части определенной строки с регулярным выражением?

Я всегда боялся регулярных выражений, но мне кажется, что я должен их изучить. Во всяком случае, я пытаюсь сделать следующее: - возьмите строку, извлеките из нее цифры и суммируйте их. Требование, что это меня беспокоит то, что один

Разрешить несколько разделителей, как это: «// [delim1] [delim2] \ п», например «// [*] [%] \ n1 * 2% 3» должен вернуться 6. Убедитесь, что вы также можете обрабатывать несколько разделителей длиной более одного символа.

Требование означает, что я должен извлечь 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); 
     } 

    } 

} 
+0

Должны ли мы рассмотреть, например. - числа с плавающей запятой или что-то вроде - '23' как одно целое число? Или вы просто хотите добавить отдельные цифры? –

+0

Я суммирую только целые числа в этом упражнении. Да, 23 будет единственным целым числом. –

+0

это может быть не java, но [страница regexp в MDN] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) помогла мне в понимании этой темы – havarc

ответ

0

Это больше, чем просто соответствие любые числа, но он должен работать для разделителей как «delim1», то есть разделители, содержащие числа. Я попытался объяснить шаблоны и шаги inline.

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

Edit/некоторые дополнительные разъяснения

Регулярное выражение \\[([^\\]]+)\\] состоит из трех частей:

  • "\\[": это будет соответствовать открывающих квадратных скобок определения разделителем. Обратите внимание на две обратные косые черты, которые необходимы, потому что они будут интерпретироваться компилятором Java. Однако мы хотим сопоставить [, который является особым символом в регулярном выражении. Поэтому нам нужны два из них.
  • ([^\\]]+): Внешние круглые скобки создают так называемую группу захвата, и вы можете позже использовать Matcher.group(n), где n является индексом группы. Таким образом, 1 будет определена первая группа, вторая - вторая и т. Д. 0 возвращает всю строку соответствия.

    • [^\\]]+: Это регулярное выражение будет соответствовать содержанию определения разделителей, то есть все, что внутри квадратных скобок. На этот раз внешние [ и ] не экранированы. Они имеют особое значение и определяют класс персонажа. Класс символов будет соответствовать любому символу, указанному внутри него. Например, [abc] будет соответствовать a или b или c, но не d. ^ в начале символьного класса имеет особое значение, он инвертирует класс символов. Таким образом, [^ abc] будет соответствовать любому персонажу , кроме, для a, b или c.

      Единственным символом, определенным в нашем классе символов, является ], поэтому класс символов будет соответствовать любому символу, за исключением закрывающей квадратной скобки, которая завершит определение разделителя. +, добавленный к классу символов, означает: совпадение не менее 1 символа или больше, если это возможно.

  • \\]: Просто совместим с закрывающей квадратной скобкой.

С помощью этого регулярного выражения мы получим строку разделителей, вызывая Matcher.find() и Matcher.group(1). String.split() также использует регулярное выражение для параметра разделителя. Итак, теперь нам нужно создать регулярное выражение, которое соответствует любой разделительной строке, которую мы раньше разбирали. Pattern.quote() используется для удаления строк разделителя. Это может потребоваться, если разделитель содержит специальный символ, который иначе интерпретируется регулярным выражением. | - такой особый символ, который является or. Вся строка регулярных выражений, которую мы построим, будет соответствовать любой строке разделителя. Поэтому String.split() разделит строки на наших разделителях.

+0

спасибо много ниф! У меня есть две строки из вашего кода, которые я не совсем понимаю: - тот, который соответствует скобкам "\\ [([^ \\]] +) \\]" - не может расшифровать его вообще, а other - Pattern.quote (mDelim.group (1)) + "|") - как это работает? –

+0

@PeshoPetrov: Я отредактировал ответ и добавил к нему больше объяснений. Я знаю, что чтение регулярного выражения, которое кто-то еще построил, довольно сложно. :) – nif

+0

ниф, ты мужчина :) –

0

Вы можете использовать регулярное выражение

\d соответствует одной цифре

+ является квант, который соответствует предыдущему шаблону 1, много раз

Таким образом, \d+ будет ma TCH 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; 
} 
Смежные вопросы