## Summing A String

### June 19, 2020

In a string consisting of digits and other non-digit characters, the digits form an embedded series of positive integers. For instance, the string “123abc45def” contains the embedded integers 123 and 45, which sum to 168.

Your task is to write a program that takes a string and writes the sum of the integers embedded in the string. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

### 22 Responses to “Summing A String”

1. Paul said

In Python.

```import re

def sumstr(txt):
return sum(int(n) for n in re.findall(r"(\d+)", txt))

txt = "77Pro123gra34mming Pra987xis is fun32"
print(sumstr(txt))  # --> 1253
```
2. chaw said

Here are two solutions in standard Scheme (R7RS). The first is a “one
liner” that uses string-tokenize from SRFI 13. The second uses only
simple Scheme. It also reliably (based on my reading of R7RS) handles
numbers in character-sets other than ASCII. (See sample inputs.)

``` (import (scheme base) (scheme write) (scheme char) (only (srfi 14) char-set:digit) (only (srfi 13) string-tokenize string-fold)) (define samples ; ((input . output) ...) '(("123abc45def" . 168) ("" . 0) ("a-123bc45xyz" . 168) ("99bottles0corks" . 99) ("१२३कखग४५घङ" . 168) ("९९बाटल्या०बुच" . 99))) (define (string-numbers-sum str) (apply + (map string->number (string-tokenize str char-set:digit)))) (define (string-numbers-sum/v2 str) (let ((len (string-length str))) (let loop ((i 0) (pnum 0) (s 0)) (if (>= i len) s (let ((c (string-ref str i))) (if (char-numeric? c) (loop (+ i 1) (+ (* 10 pnum) (digit-value c)) s) (loop (+ i 1) 0 (+ s pnum)))))))) (define (demo f) (write (equal? (map cdr samples) (map f (map car samples)))) (newline)) (demo string-numbers-sum) (demo string-numbers-sum/v2) ```

Output:

``` #t #t ```

3. matthew said

Here’s some Haskell. Scan the string accumulating digits, when a complete number is found, use base-10 arithmetic to add number into running total:

```import Data.Char

getdigit c | isDigit c = Just(digitToInt(c)) | otherwise = Nothing

adc 0 [] t = t
adc carry (m:s) (n:t) = mod : adc div s t where (div,mod) = divMod (carry+m+n) 10

scan1 sum stack s = scan (adc 0 sum stack) [] s
scan sum [] [] = reverse sum
scan sum stack [] = scan1 sum stack []
scan sum stack (Just d : s) = scan sum (d:stack) s
scan sum stack (Nothing : s) = scan1 sum stack s

main = print (scan [] [] (map getdigit "123abc45def")) -- [1,6,8]
```
4. Globules said

Here’s another Haskell version, using splitWhen from the “split” library.

```import Data.Char (isDigit)
import Data.List.Split (splitWhen)

sumstr :: (Integral a, Read a) => String -> a
sumstr = sum . map read . filter (not . null) . splitWhen (not . isDigit)

main :: IO ()
main = do
print \$ sumstr "123abc45def"
print \$ sumstr "xy123abc45def"
print \$ sumstr ""
```
```\$ ./sumstr
168
168
0
```
5. Daniel said

Here’s a shell script solution. `sed` is combined with `tr` to replace repeated non-digit characters with a `+`. This could alternatively be achieved by passing `sed`‘s flag for extended regex, and checking for one or more non-digit characters.

```#!/usr/bin/env sh

echo "0 \$1 0" | sed 's/[^0-9]/+/g' | tr -s '+' | bc
```

Example:

```\$ ./sum.sh 123abc45def
168
\$ ./sum.sh
0
```
6. Daniel said

Here’s a solution in C.

```#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Overflow is not checked/handled.
int main(int argc, char* argv[]) {
assert(argc == 2);
int sum = 0;
int multiplier = 1;
int n = strlen(argv);
for (int i = n - 1; i >= 0; --i) {
char c = argv[i];
if (c < '0' || c > '9') {
multiplier = 1;
continue;
}
sum += multiplier * (int)(c - '0');
multiplier *= 10;
}
printf("%d\n", sum);
return EXIT_SUCCESS;
}
```

Example:

```\$ ./a.out asdf123abc45def
168
```
7. matthew said

@Daniel – nice solutions, scanning the string in reverse is a good idea, here’s a simplified version of my “elementary” Haskell solution:

```import Data.Char

getdigit c | isDigit c = Just(digitToInt(c)) | otherwise = Nothing

add d (a:s) = mod : add div s where (div,mod) = divMod (a+d) 10
scan1 [] stack s = scan [] (0:stack) s
scan1 (d:sum) stack s = scan sum (d:stack) s
scan sum stack (Just d : s) = scan1 (add d sum) stack s
scan sum stack (Nothing : s) = scan ((reverse stack) ++ sum) [] s
scan sum stack [] = (reverse sum) ++ stack

main = print (scan [] [] (reverse (map getdigit "123abc450def"))) -- [1,6,8]
```
8. matthew said

I left an extra “0” in the test data there, so the result is actually “[5,7,3]”.

9. Xero said

Here’s a simple solution: get a list of numbers in the string, then add them up. A Commonlisp implementation:

```(defun split-string (str &key (pred #'(λ (c) (char= c #\space))))
"return a list of substrings of str delimited at positions where pred is T.
The charcters at the point where pred is T are not included"
(do ((i (1- (length str)) (1- i))
(current nil)
(acc nil))
((< i 0) (or (and (null current) acc)
(cons (coerce current 'string) acc)))
(let ((c (char str i)))
(cond ((funcall pred c)
(unless (null current)
(push (coerce current 'string) acc))
(setf current nil))
(t (push c current))))))

(defun sum-numbers-in-string (str)
"return the sum of the numbers in str where each number is contigous."
(reduce #'(λ (a b) (+ a (parse-integer b)))
(split-string str :pred #'alpha-char-p)
:initial-value 0))
```
10. matthew said

A different approach in Python:

```>>> f = lambda s: eval(re.sub("[^0-9]+","+",s).strip("+"))
>>> f("123abc45def")
168
```
11. matthew said

Actually, that’s rather like Daniel’s shell solution.

12. Tamil said

Here is a different solution:

#123abc45def
st = input(“Enter string”)
sum_val = 0
msg = ”
for i in st:
if ord(i)>47 and ord(i)< 58:
msg+=i
else:
if msg!=”:
sum_val+=int(msg)
msg=”
else:
continue
print(sum_val)

13. Maksym Fedenko said

public class Exercises_2 {
public static void main(String[] args) {
class Input{
public String inputString(){
Scanner scanner = new Scanner(System.in);
return scanner.nextLine();
}
public int string_in_int_out(String s){
int sum = 0;
char [] inputValue = s.toCharArray();
char [] numbers = new char [inputValue.length + 1];
for (int i = 0; i < inputValue.length; i++) {
if (Character.isDigit(inputValue[i])){
numbers[i] = inputValue[i];
}else {
continue;
}
}
String buffer = “”;
for (int i = 0; i < numbers.length; i++) {
if (!Character.isDigit(numbers[i])){
continue;
}else if(Character.isDigit(numbers[i])){
buffer += numbers[i];
if (!Character.isDigit(numbers[i + 1])){
sum += Integer.parseInt(buffer);
buffer = “”;
}
}
}
return sum;
}
}
Input input = new Input();
System.out.println(input.string_in_int_out(input.inputString()));
}
}

14. Maksym Fedenko said

Hi guys how I can post my solutions like a code?

15. Daniel said

Here’s another solution in C.

```#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

// Overflow is not checked/handled.
int main(int argc, char* argv[]) {
assert(argc == 2);
long sum = 0;
while (*argv) {
sum += strtol(argv, &argv, 10);
if (*argv) ++(argv);
}
printf("%ld\n", sum);
return EXIT_SUCCESS;
}
```

Example:

```\$ ./a.out asdf123abc45def
168
```
16. V said

A bit late to the party…here is a one liner in Ruby:

```puts ARGV.first.scan(/\d+/).map(&:to_i).sum
```

Example:

```ruby sum-string.rb '123abc45def'
168
```
17. solution in Clojure with transducer:

```(ns stringsum.core
(:require [clojure.string :as string]
[clojure.edn :as edn])
(:gen-class))

(defn sum-numbers [str]
(let [xf (comp (filter (complement string/blank?))
(transduce xf + 0 (string/split str #"[a-zA-Z]+"))))
```
18. Although the regex should better be #”[^\d+]”

19. Larry Lee said

```strSum = snd . foldr (\c (n, x) -> if isDigit c then (n + 1, (digitToInt c) * 10^n + x) else (0, x)) (0, 0)
```
20. Humberto Rondon said

Here’s mine in Perl, using regexes

```use strict;
use warnings;
use List::Util qw(reduce);

my \$str = "123abc45def";

print (reduce { \$a + \$b } (\$str =~ /(\d+)/g));
```
21. Hakan said
```
if (!empty(\$_POST['string'])) {
\$string = \$_POST['string'];

preg_match_all('/\d+/', \$string, \$matches);

\$total = 0;
foreach (\$matches as \$match) {
foreach (\$match as \$integer) {
\$total += \$integer;
}
}

echo "<pre>";
var_dump(\$matches);

echo "The sum of all integers in the string that you have entered is: ".\$total;

}

?>

<!DOCTYPE html>
<html>