Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
May 30, 2006 Phobos addition - std.conv.toInt(char[] s, int base) | ||||
---|---|---|---|---|
| ||||
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 30, 2006 Probably does not work as intended | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | "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 Re: Probably does not work as intended | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bob W | "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. |
Copyright © 1999-2021 by the D Language Foundation