-3

I have couple of similar strings. I want to extract the numbers from them, add the numbers and convert it back to the same string format.

And the logic should be generic, i.e., it should work for any given strings.

Example:

String s1 = "1/9";
String s2 = "12/4";

The total of the above two Strings should be "13/13" (String again)

I know how to extract numbers from any given String. I referred: How to extract numbers from a string and get an array of ints?

But I don't know how to put them up back again to the same String format.

Can any one please help me over this?

Note: the string format can be anything, I have just taken an example for explanation.

Community
  • 1
  • 1
Viraj Pai
  • 205
  • 3
  • 11
  • So the string format is just that numbers can be fractions? – Kristjan Veskimäe Apr 04 '14 at 08:12
  • What should be the output of "1/9", "12\4"? Or is it always the same 'string format'? What happens if it is not? – amit Apr 04 '14 at 08:12
  • 1
    split each string on a regular expression for non-number (`[^0-9]`). Add each array numbered item to the next array's item at the same index. Then join on the original delimiter? The only way you're going to be able to make that work though is if you have the same number of split objects. – brandonscript Apr 04 '14 at 08:12

6 Answers6

1

Take a look at this:

public class StringTest {

    public static void main(String[] args) {
        String divider = "/";

        String s1 = "1/9";
        String s2 = "12/4";

        String[] fragments1 = s1.split(divider);
        String[] fragments2 = s2.split(divider);

        int first = Integer.parseInt(fragments1[0]);
        first += Integer.parseInt(fragments2[0]);

        int second = Integer.parseInt(fragments1[1]);
        second += Integer.parseInt(fragments2[1]);

        String output = first + divider + second;
        System.out.println(output);
    }
}

The code prints:

13/13

Markus
  • 1,649
  • 1
  • 22
  • 41
  • `Note: the string format can be anything, I have just taken an example for explanation.` This fails for anything other than `"/"`. The OP want it generalized, so you need an arbitrary delimeter - and be able to reproduce it. Your answer does NOT take it into account. – amit Apr 04 '14 at 08:14
  • Exactly that! Except you may want to have it split on a regular expression. – brandonscript Apr 04 '14 at 08:15
  • @amit: I updated the code. Now the `divider` can be set to any string – Markus Apr 04 '14 at 08:17
  • @remus And need to be able to reproduce the (unknown at compile time) delimeter. This answer only answers the specific example, not the question. – amit Apr 04 '14 at 08:18
  • @Markus No, it is not. The thing is you have no idea at compile time what `divider` is, from my understanding of the question. You need to find it on the fly, and get it back, dynamically. – amit Apr 04 '14 at 08:18
  • @amit hence splitting on a regular expression for "not-numeric" `[^0-9]`, which will treat anything as a delimiter. – brandonscript Apr 04 '14 at 08:18
  • @remus and using grouping or something to get it back in order to rebuild the string. This can be done, but it's not "exactly that" and this answer is lacking very important aspects from the question. – amit Apr 04 '14 at 08:19
  • In addition, I did see in the question where he asked for length 2 only support, it should be replaced with a dynamic loop instead of hard coded `first`,`second` - which is code duplication and a bad coding practice anyway. – amit Apr 04 '14 at 08:24
1

Using a regex (and Markus' code)

public class StringTest {

    public static void main(String[] args) {
        String s1 = "1/9";
        String s2 = "12&4";

        String[] fragments1 = s1.split("[^\\d]");

        String[] fragments2 = s2.split("[^\\d]");

        int first = Integer.parseInt(fragments1[0]);
        first += Integer.parseInt(fragments2[0]);

        int second = Integer.parseInt(fragments1[1]);
        second += Integer.parseInt(fragments2[1]);

        String output = first + divider + second;
        System.out.println(output);
    }
}

You should be able to get from here to joining back from an array. If you're getting super fancy, you'll need to use regular expression capture groups and store the captured delimiters somewhere.

Community
  • 1
  • 1
brandonscript
  • 68,675
  • 32
  • 163
  • 220
  • divider is undefined. You need to find it dynamically, one more step is missing for a valid answer. – amit Apr 04 '14 at 08:21
  • It is important because you want to print them in the same format, if it was `1/2+3`, this format should remain. The hardcoded `first`,`second` should also be arbitrary length, I didn't see anywhere in the answer mentioning the length should be 2. – amit Apr 04 '14 at 08:24
  • I am very familiar with it, this is basically what I am directing you to do in order to produce a good answer and not only half-baked one. – amit Apr 04 '14 at 08:25
  • You do know I am not the OP right? I am just a high-rep user, and one of the most active under the 'algorithm' tag, who cares about the community and want to help building a non-misleading knowledge base in it. – amit Apr 04 '14 at 08:29
  • I am far from suggesting it, but if you do provide a code (which does not compile, btw) - it should do what it was asked to. I have no problems with an answer giving only the tools without any code nor with pseudo-code, but finding back the format required is the core of the question, or at the very least an important aspect of it, and there is simply not enough content in your answer that supports this aspect. Even reference to the relevant methods' documnetation with brief explanation what they do should suffice, IMO. – amit Apr 04 '14 at 08:41
1

First, split your strings into matches and non-matches:

  public static class Token {
    public final String text;
    public final boolean isMatch;

    public Token(String text, boolean isMatch) {
      this.text = text;
      this.isMatch = isMatch;
    }

    @Override
    public String toString() {
      return text + ":" + isMatch;
    }
  }

  public static List<Token> tokenize(String src, Pattern pattern) {
    List<Token> tokens = new ArrayList<>();
    Matcher matcher = pattern.matcher(src);
    int last = 0;
    while (matcher.find()) {
      if (matcher.start() != last) {
        tokens.add(new Token(src.substring(last, matcher.start()), false));
      }
      tokens.add(new Token(src.substring(matcher.start(), matcher.end()), true));
      last = matcher.end();
    }
    if (last < src.length()) {
      tokens.add(new Token(src.substring(last), false));
    }
    return tokens;
  }

Once this is done, you can create lists you can iterate over and process.

For example, this code:

Pattern digits = Pattern.compile("\\d+");
System.out.println(tokenize("1/2", digits));

...outputs:

[1:true, /:false, 2:true]
McDowell
  • 107,573
  • 31
  • 204
  • 267
0

Damn quick and dirty not relying on knowing which separator is used. You have to make sure, m1.group(2) and m2.group(2) are equal (which represents the separator).

public static void main(String[] args) {
    String s1 = "1/9";
    String s2 = "12/4";
    Matcher m1 = Pattern.compile("(\\d+)(.*)(\\d+)").matcher(s1);
    Matcher m2 = Pattern.compile("(\\d+)(.*)(\\d+)").matcher(s2);
    m1.matches(); m2.matches();
    int sum1 = parseInt(m1.group(1)) + parseInt(m2.group(1));
    int sum2 = parseInt(m2.group(3)) + parseInt(m2.group(3));
    System.out.printf("%s%s%s\n", sum1, m1.group(2), sum2);
}
Harmlezz
  • 7,972
  • 27
  • 35
  • Best answer yet IMO, but it is still lacking the fact that the length should be dynamic. From my understanding you need to also support `1/2\3`, for example – amit Apr 04 '14 at 08:27
  • You mean, supporting the occurrence of more than two numbers in a string? – Harmlezz Apr 04 '14 at 08:31
  • Yeap, it seems to me you need to support it (the body of the question say strings with delimeters, not 2 numbers - this implicit assumption comes from the example, we want to answer the question, not the example) – amit Apr 04 '14 at 08:32
0

Consider function:

public String format(int first, int second, String separator){
    return first + separator + second;
}

then:

System.out.println(format(6, 13, "/")); // prints "6/13"
Bartek Maraszek
  • 1,404
  • 2
  • 14
  • 31
0

Thanks @remus. Reading your logic I was able to build the following code. This code solves the problem for any given strings having same format.

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

    ArrayList<Integer> numberList1 = new ArrayList<Integer>();
    ArrayList<Integer> numberList2 = new ArrayList<Integer>();
    ArrayList<Integer> outputList = new ArrayList<Integer>();

    String str1 = "abc 11:4 xyz 10:9";
    String str2 = "abc 9:2  xyz 100:11";

    String output = "";

    // Extracting numbers from the two similar string
    Pattern p1 = Pattern.compile("-?\\d+");

    Matcher m = p1.matcher(str1);
    while (m.find()) {
        numberList1.add(Integer.valueOf(m.group()));
    }

    m = p1.matcher(str2);
    while (m.find()) {
        numberList2.add(Integer.valueOf(m.group()));
    }

    // Numbers extracted. Printing them
    System.out.println("List1: " + numberList1);
    System.out.println("List2: " + numberList2);

    // Adding the respective indexed numbers from both the lists
    for (int i = 0; i < numberList1.size(); i++) {
        outputList.add(numberList1.get(i) + numberList2.get(i));
    }

    // Printing the summed list
    System.out.println("Output List: " + outputList);

    // Splitting string to segregate numbers from text and getting the format
    String[] template = str1.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");

    // building the string back using the summed list and format
    int counter = 0;
    for (String tmp : template) {
        if (Test.isInteger(tmp)) {
            output += outputList.get(counter);
            counter++;
        } else {
            output += tmp;
        }
    }

    // Printing the output
    System.out.println(output);
}

public static boolean isInteger(String s) {
    try {
        Integer.parseInt(s);
    } catch (NumberFormatException e) {
        return false;
    }
    return true;
}

}

output:

List1: [11, 4, 10, 9]
List2: [9, 2, 100, 11]
Output List: [20, 6, 110, 20]
abc 20:6 xyz 110:20

Viraj Pai
  • 205
  • 3
  • 11