s c h e m a t i c s : c o o k b o o k

/ StringChapter / Cookbook.StringNumber

This Web


WebHome 
WebChanges 
TOC (with recipes)
NewRecipe 
WebTopicList 
WebStatistics 

Other Webs


Chicken
Cookbook
Erlang
Know
Main
Plugins
Sandbox
Scm
TWiki  

Schematics


Schematics Home
Sourceforge Page
SchemeWiki.org
Original Cookbook
RSS

Scheme Links


Schemers.org
Scheme FAQ
R5RS
SRFIs
Scheme Cross Reference
PLT Scheme SISC
Scheme48 SCM
MIT Scheme scsh
JScheme Kawa
Chicken Guile
Bigloo Tiny
Gambit LispMe
GaucheChez

Lambda the Ultimate
TWiki.org

Testing Whether a String Represents an Integer

Problem

You want to determine whether a string is an integer

Solution

string->integer STRING START END -> INTEGER or #f
(define (string->integer str start end)
  (and (< -1 start end (inc (string-length str)))
    (let loop ((pos start) (accum 0))
      (cond
        ((>= pos end) accum)
        ((char-numeric? (string-ref str pos))
          (loop (inc pos) (+ (char->integer (string-ref str pos)) 
              (- (char->integer #\0)) (* 10 accum))))
        (else #f)))))

Here inc is a macro or a function that returns the incremented argument. On many Scheme systems, it can be implemented more efficiently than merely (+ 1 x) if we assume that x is a fixnum.

Discussion

This procedure checks to see if a substring of STRING from START (inclusive) till END (exclusive) is a representation of a non-negative integer in decimal notation. If this is the case, this integer is returned.

Otherwise -- when the substring contains non-decimal characters, or when the range from START till END is not within STRING, the result is #f.

This procedure is a specialization of the standard string->number. The latter is far more general: for example, it will try to read strings like "1/2", "1S2", "1.34" and even "1/0" (the latter causing a zero-divide error). Note that to string->number, "1S2" is a valid representation of an inexact integer 100. Oftentimes we want to be more restrictive about what we consider a number: we want merely to read an integral label.

The obvious method is to use R5RS string->number as a test. string->number can convert strings containing base 2, 8, 10, and 16 numbers into a number. You can also force a conversion by formatting the number using Scheme conventions for specifying bases. If the conversion can't be performed, string->number returns #f:

> (string->number "1234")
1234
> (string->number "abc" 16)
2748
> (string->number "77" 8)
63
> (string->number "abc" )
#f
> (string->number "123abc")
#f
> (string->number "778" 8)
#f
> (string->number "#o11" )
9
> (string->number "#x11" )
17
This is only half the solution, however. string->number works for any kind of number, so technically, you should wrap the call in a call to the integer? predicate:
> (integer? (string->number "77" ))
#t
> (integer? (string->number "77.7" ))
#f

However, the simple solution has some notable drawbacks. It must be noted that using string->number for testing if a string represents an integer has notable drawbacks. Scheme's concept of number is a lot broader than most languages', so string->number is much more general than your typical programming language. Scheme understands arbitrarily large numbers like 2 ^ 80, fractions such as 1/2, and imaginary numbers:

> (string->number "1208925819614629174706176")
1208925819614629174706176
> (string->number "1/2")
1/2
> (string->number "0+1i")
0+1i

Scheme's number facilities can lead to surprises. For example, on Petite Chez Scheme and Gambit,

> (string->number "1S0")
1.0
> (integer? (string->number "1S0"))
#t
Not too many people would take "1S0" to mean an integer. It means an inexact integer.

There is even more serious problem. Often we test if a string represents an integer when validating user input. It is highly preferable if the test is a total predicate, that is, generates no errors. However, (string->number "1/0") will raise a run-time error.

-- OlegK - 14 Sep 2004 (corrected solution) -- GordonWeakliem - 23 Apr 2004 (simple solution)

References

http://pobox.com/~oleg/ftp/Scheme/util.html#misc-str-util

Comments

Oleg, two points: your text is below the STOPINCLUDE directive, which is where comments are supposed to live; this page would be more useful to the reader if you worked your correct solution into the body of the text with Gordon's solution. I don't have time right now to make these changes or I would do them myself -- NoelWelsh - 14 Sep 2004

I moved STOPINCLUDE; thank you for clarifying it. I thought about how to merge two solutions, and the best I have come with is to add one level of headers, and make a forward reference. Any hints how to do the merging better? Both solutions will work, depending on circumstances

-- OlegK - 14 Sep 2004

My preference is to give the correct solution (i.e. Oleg's) under solution and put the rest under discussion. In this case, I put the discussion of the correct solution first and then went into a discussion of Scheme's number system, which leads into why string->number is insufficient. Also, the definition of inc seems worthy of a recipe of its own under NumberRecipes, I think.

-- GordonWeakliem - 14 Sep 2004

Note that inc is called add1 in MzScheme. In my opinion the portable solution (+ x 1) is in the context of a cookbook better (easier to grasp). Besides, most compilers ought to recognize this pattern anyway.

-- JensAxelSoegaard - 14 Sep 2004

Thank you both! Perhaps indeed one ought to use (+ x 1) in the context of the cookbook. Regarding compiler's recognizing that pattern: Gambit and Bigloo are pretty good Scheme compilers. And yet, if one looks into their source code, one sees (##fixnum.+ 1 index) (in Gambit) or (+fx 1 escape-mark) (in Bigloo) all over the place. Incidentally, OCaml has int->int primitives succ and pred, which are heavily used in its own source code. That is a bit surprising considering that arithmetical operations in Ocaml are monomorphic and 1 + x is easier to type.

-- OlegK - 15 Sep 2004

CookbookForm
TopicType: Recipe
ParentTopic: StringRecipes
TopicOrder: 200

 
 
Copyright © 2004 by the contributing authors. All material on the Schematics Cookbook web site is the property of the contributing authors.
The copyright for certain compilations of material taken from this website is held by the SchematicsEditorsGroup - see ContributorAgreement & LGPL.
Other than such compilations, this material can be redistributed and/or modified under the terms of the GNU Lesser General Public License (LGPL), version 2.1, as published by the Free Software Foundation.
Ideas, requests, problems regarding Schematics Cookbook? Send feedback.
/ You are Main.guest