2

I'm trying to convert strings that match /(\d)+(\.\d+)?(m|g|t)?b?/i into bytes.

For example, 1KB would return 1024. 1.2mb would return 1258291.

fent
  • 17,861
  • 15
  • 87
  • 91

3 Answers3

7

If you reorganize the capturing group in your regex like so: /(\d+(?:\.\d+)?)\s?(k|m|g|t)?b?/i you can do something like:

function unhumanize(text) { 
    var powers = {'k': 1, 'm': 2, 'g': 3, 't': 4};
    var regex = /(\d+(?:\.\d+)?)\s?(k|m|g|t)?b?/i;

    var res = regex.exec(text);

    return res[1] * Math.pow(1024, powers[res[2].toLowerCase()]);
}

unhumanize('1 Kb')
# 1024
unhumanize('1 Mb')
# 1048576
unhumanize('1 Gb')
# 1073741824
unhumanize('1 Tb')
# 1099511627776
mouad
  • 67,571
  • 18
  • 114
  • 106
  • If you stored powers of 2 in the table instead of powers of 1024, you could use a bitshift for the calculation (which is generally much faster that the power function). – Ben Voigt Aug 07 '11 at 18:38
  • @vol7ron: You should take that complaint up with the question which uses them interchangeably, not the answer. – Ben Voigt Aug 07 '11 at 18:38
  • @ben: I take it up with both, and will change the vote when it has changed, otherwise not a bad solution – vol7ron Aug 07 '11 at 18:39
  • @Ben : sadly the bit shifting in javascript is mostly 32 bit (depending on the js engine of course) http://stackoverflow.com/questions/2373791/bitshift-in-javascript so : `1 << 32 === 1`. – mouad Aug 07 '11 at 19:02
  • @vol7ron: Thanks for the feed back i didn't see that -:) well hope the OP have seen that and will correct my leak . – mouad Aug 07 '11 at 19:05
  • @mouad: That's unfortunate :( And so 1992. – Ben Voigt Aug 07 '11 at 20:01
  • Works great but I'm not sure it handles numbers that are less than 1k (my use case is creating a D3 graph from `du -h` output). – Sridhar Sarnobat Mar 24 '16 at 05:37
3

You've already got a capturing group for the unit prefix, now all you need is a lookup table:

{ 'k', 1L<<10 },
{ 'M', 1L<<20 },
{ 'G', 1L<<30 },
{ 'T', 1L<<40 },
{ 'P', 1L<<50 },
{ 'E', 1L<<60 }

Demo: http://ideone.com/5O7Vp

Although 1258291 is clearly far too many significant digits to get from 1.2MB.

oops, I gave a C# example. The method is still good though.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

One liner solution:

"1.5 MB".replace(/(\d+)+(\.(\d+))?\s?(k|m|g|t)?b?/i, function(value, p1, p2, p3, p4) { return parseFloat(p1 + (p2 || ""))*({ 'K' : 1<<10, 'M' : 1<<20, 'G' : 1<<30, 'T' : 1<<40 }[p4] || 1); })

# 1572864
edtech
  • 1,734
  • 20
  • 20