digitalmars.D - Phobos addition - std.conv.toInt(char[] s, int base)
- Jarrett Billingsley (73/73) May 29 2006 I've been missing the ability to convert any base of string numerical
- Bob W (55/61) May 30 2006 Unless you specifically intend to get identical results
- Jarrett Billingsley (3/7) May 30 2006 Ooh, how insidious. Thanks for catching that.
I've been missing the ability to convert any base of string numerical literal into an int (i.e. strtol()), so I wrote a new toInt that allows any base from 2 to 36 (bases greater than 10 use a-z, case-insensitive). It accomplishes this by using a translation table (generated by std.string.maketrans() of course) for easy parsing. It's written pretty much the same way that the existing toInt is. int toInt(char[] s, int base) { assert(base >= 2 && base <= 36); static char[] transTable = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 91, 92, 93, 94, 95, 96, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 ]; int length = s.length; if(!length) throw new ConvError(s); int sign = 0; int v = 0; char maxDigit = '0' + base - 1; for(int i = 0; i < length; i++) { char c = transTable[s[i]]; if(c >= '0' && c <= maxDigit) { uint v1 = v; v = v * base + (c - '0'); if(cast(uint)v < v1) throw new ConvOverflowError(s); } else if(c == '-' && i == 0) { sign = -1; if(length == 1) throw new ConvError(s); } else if(c == '+' && i == 0) { if(length == 1) throw new ConvError(s); } else throw new ConvError(s); } if(sign == -1) { if(cast(uint)v > 0x80000000) throw new ConvOverflowError(s); v = -v; } else { if(cast(uint)v > 0x7FFFFFFF) throw new ConvOverflowError(s); } return v; }
May 29 2006
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message news:e5gcr4$27r5$1 digitaldaemon.com...I've been missing the ability to convert any base of string numerical literal into an int (i.e. strtol()), so I wrote a new toInt that allows any base from 2 to 36 (bases greater than 10 use a-z, case-insensitive). It accomplishes this by using a translation table (generated by std.string.maketrans() of course) for easy parsing. It's written pretty much the same way that the existing toInt is.Unless you specifically intend to get identical results for e. g. toInt(";:=",16) and toInt("BAD",16) , you need to exclude a certain character range from conversion. Have a look at this one: ------------ int toInt(char[] s, int base) { const char XX=0xff; const char[256] transTable = [ XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX,XX,XX,XX,XX, XX,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31,32,33,34,35,26,XX,XX,XX,XX, XX,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31,32,33,34,35,26,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX ]; assert (base>0 && base<37); int length = s.length; if (!length) throw new ConvError(s); uint minus = 0, v = 0; foreach (i, c; s) { char ct=transTable[c]; if (ct<base) { uint v1 = v; v = v*base + ct; if (v<v1) throw new ConvOverflowError(s); } else if (!i) { if (c == '-') minus=1; else if (c != '+') throw new ConvError(s); } else throw new ConvError(s); } if (v & 0x80000000) { if (!minus) throw new ConvOverflowError(s); if (v & 0x7fffffff) throw new ConvOverflowError(s); } return cast(int)(minus ? 0-v : v); } ----------------- Please note that my sample program accepts a base of 1. This is still a valid base but it probably has no practical merits.
May 30 2006
"Bob W" <nospam aol.com> wrote in message news:e5h97s$muj$1 digitaldaemon.com...Unless you specifically intend to get identical results for e. g. toInt(";:=",16) and toInt("BAD",16) , you need to exclude a certain character range from conversion.Ooh, how insidious. Thanks for catching that.
May 30 2006