{"id":45271,"date":"2015-06-29T07:00:00","date_gmt":"2015-06-29T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20150629-00\/?p=45271\/"},"modified":"2019-03-13T12:16:48","modified_gmt":"2019-03-13T19:16:48","slug":"20150629-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150629-00\/?p=45271","title":{"rendered":"Parsing a string as a 64-bit integer, somehow"},"content":{"rendered":"<p>Today&#8217;s Little Program takes a string and tries to parse it as a 64-bit integer in formats that a programmer would likely encounter. <\/p>\n<p>Here&#8217;s a first stab: <\/p>\n<pre>\nusing System;\nusing System.Globalization;\n\nclass Program\n{\n static long ParseLongSomehow(string s)\n {\n  if (s.StartsWith(\"0x\", StringComparison.OrdinalIgnoreCase)) {\n   return long.Parse(s.Substring(2), NumberStyles.HexNumber);\n  } else {\n   return long.Parse(s);\n  }\n }\n\n public static void Main(string[] args)\n {\n  long value = ParseLongSomehow(args[0]);\n  Console.WriteLine(value);\n  Console.WriteLine(\"0x{0:X}\", value);\n }\n}\n<\/pre>\n<p>If the string begins with <code>0x<\/code>, then we treat the rest of the argument as a hex value; otherwise, we treat it as a decimal value. <\/p>\n<p>Unfortunately, this doesn&#8217;t work if the input is <code>9223372036854775808<\/code>, which is the value of <code>1 &lt;&lt; 63<\/code>, a value that is representable as a 64-bit unsigned value but not a 64-bit signed value. <\/p>\n<p>Our problem statement was pretty vague, so let&#8217;s <a HREF=\"http:\/\/blogs.msdn.com\/b\/ericlippert\/archive\/2009\/11\/19\/always-write-a-spec-part-one.aspx\">write a functional specification<\/a>. It helps to know what problem you&#8217;re solving before you start to solve it. Otherwise, you&#8217;re just flailing around writing code <a HREF=\"http:\/\/ericlippert.com\/2014\/03\/05\/how-to-debug-small-programs\/\">before you have a plan<\/a>. When I tried to solve this problem, I flailed around a bit until I realized that I didn&#8217;t have a spec. <\/p>\n<p>What formats would a programmer be likely to encounter as the string representation of a 64-bit integer? <\/p>\n<ul>\n<li><code>0x1234<\/code>: 64-bit number in hex format,     case-insensitive.     The value can range from 0 to <code>UInt64.MaxValue<\/code>. \n<li><code>12345<\/code>: 64-bit unsigned number in decimal format.     The value can range from 0 to <code>UInt64.MaxValue<\/code>. \n<li><code>-12345<\/code>: 64-bit signed number in decimal format.     The value can range from <code>Int64.MinValue<\/code>     to <code>Int64.MaxValue<\/code>. \n<li>Other formats may be permitted, but you need to support at     least the above. <\/ul>\n<p>Writing down exactly what I was doing and what I wasn&#8217;t doing was the part that solved my flailing. I had been worrying about things like <code>-0x12345<\/code> and <code>-9223372036854775809<\/code> and <code>9999999999999999999<\/code>, even though those numbers would not be something a programmer would be likely to encounter. <\/p>\n<p>From the specification we can develop our algorithm. <\/p>\n<ul>\n<li>If the string begins with <code>0x<\/code>, then     parse what&#8217;s left as an unsigned 64-bit hexadecimal number. \n<li>If the string begins with a minus sign, then parse     it as a 64-bit signed number in decimal format. \n<li>If the string does not begin with a minus sign, then parse     it as a 64-bit unsigned number in decimal format. <\/ul>\n<p>And that is pretty easy to implement. <\/p>\n<pre>\n static long ParseLongSomehow(string s)\n {\n  if (s.StartsWith(\"0x\", StringComparison.OrdinalIgnoreCase)) {\n   return long.Parse(s.Substring(2), NumberStyles.HexNumber);\n  } else if (s[0] == '-') {\n   return long.Parse(s);\n  } else {\n   return (long)ulong.Parse(s);\n  }\n }\n<\/pre>\n<p>Note that we are a little sloppy with our treatment of whitespace. We accept leading and trailing spaces on decimal values, and allow trailing spaces on hex values (and even allow spaces between the <code>0x<\/code> and the first hex digit). That&#8217;s okay, because the spec allows us to accept formats beyond the ones listed. <\/p>\n<p>Now, for bonus points, let&#8217;s revise the functional specification a little bit, specifically by adding another case: <\/p>\n<ul>\n<li><code>0x12`3456789A<\/code>: 64-bit number in hex format,     case-insensitive, with backtick separating the upper 32 bits     from the lower 32 bits. <\/ul>\n<p>This is the format used by the Windows debugger engine. <\/p>\n<pre>\n static long ParseLongSomehow(string s)\n {\n  if (s.StartsWith(\"0x\", StringComparison.OrdinalIgnoreCase)) {\n   return long.Parse(s.Substring(2)<font COLOR=\"blue\">.Replace(\"`\", \"\")<\/font>, NumberStyles.HexNumber);\n  } else if (s[0] == '-') {\n   return long.Parse(s);\n  } else {\n   return (long)ulong.Parse(s);\n  }\n }\n<\/pre>\n<p>We&#8217;ll leave it here for now. Next time, we&#8217;ll start putting some blocks together. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Signed or unsigned, I don&#8217;t care.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-45271","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Signed or unsigned, I don&#8217;t care.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/45271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=45271"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/45271\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=45271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=45271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=45271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}