# scanf

Definition: | sequence paramsets = scanf(string s, string fmt)
Description: | Attempt to find a sequence for which sprintf(fmt,params) could have produced s.
pwa/p2js: | Supported.
Comments: | May return more than one set, for example
        res = scanf("one two three","%s %s") -- res is {{"one","two three"},{"one two","three"}}
Note that scanf relies heavily on literal separators, especially spaces. It is illegal to specify back-to-back strings, integers, or atoms with format strings such as "%s%s", "%d%d", "%s%d", etc. The one exception is that a string can immediately follow a number, an example of which is "4th" and "%d%s". Theoretically it might be possible to write a scanf that yields {{1,23},{12,3}} from scanf("123","%d%d") but I for one cannot think of a single practical use, and getting {{"","AB"},{"A","B"},{"AB",""}} from scanf("AB","%s%s") is also of highly questionable worth. Likewise it is deemed completely unnecessary to be able to get {"hello",12} from "hello12", which proves hard, as opposed to getting that same result from "hello 12", which is trivial. Should this routine not quite meet your needs, you are strongly advised to write your own ditty: even the most basic assumption about what to expect can make that exponentially easier than modifying fully generic code, see also the final remark. Any width/precision/justify/zerofill details are for the most part quietly ignored: you may get the same results from %d/%d/%d as %02d/%02d/%04d, but obviously the latter might make the intent clearer. If scanf is about to return several possibilities, it tests the results of sprintf and trims the result set down to those with an exact character-by-character match, as long as that last pass does not trim the result set down to zero. For more details regarding format strings please refer to printf. All characters not part of a %-group are treated as literal. The d/x/o/b formats can be explicitly overriden within s such that scanf("#FF","%d") and scanf("255","%d") both succeed, as do scanf("#FF","#%x"), scanf("#FF","%x") and scanf("FF","%x"), with the first of those explicitly un-overriding the base, and the last providing the base to use in the format only. Failure is indicated by {}. Otherwise each element of the results has as many elements as there were format specifications in the format string, in the same order as specfied. A perfect unique and unambiguous result is indicated by length(res)=1. If you are confident of success, and happy to take the first should more than one result set be returned, then
        {{x,y}} = scanf(line,"%d %d")
is the typical syntax. The double braces are needed to select the first of several possible result sets (not that I can imagine any case where "%d %d" would generate more than one result, but other formats might). Of course
        sequence res = scanf(line,"%d %d")
        if length(res)=0 (or !=1) then return/exit/error end if
        {{x,y}} = res
is the safer way, again needing the double braces. The parse_date_string() function of timedate is a much better way to process date and time strings. (programming note: %s is all the wildcard-matching we can handle; ? and * are just literals.)
Example 1: |
    function isNumber(string s)
        return scanf(s,"%f")!={}
    end function
Example 2: |
    ?scanf("file_name.gif","file_%s.%s")        -- {{"name","gif"}}
    ?scanf("file_test.name.gif","file_%s.%s")   -- {{"test","name.gif"},{"test.name","gif"}}
Implementation: | See builtins\scanf.e (an autoinclude) for details of the actual implementation.
See Also: | printf, sprintf, timedate, parse_date_string
Technicalia | The C routine scanf reads from stdin; this is much closer to the C routine sscanf, but is not particularly based on either. There are some obvious deficiencies in this routine, for instance there is no (easy) way to get {r,g,b} from "#RRGGBB": feel free to try and improve it, however it is probably one of those routines that someone somewhere will always be able to think of yet something else it could or should do.