【问题标题】:Parse human-readable filesizes into bytes将人类可读的文件大小解析为字节
【发布时间】:2017-08-09 11:53:20
【问题描述】:
example_strings = ["10.43 KB", "11 GB", "343.1 MB"]

我想将所有这些字符串转换为字节。到目前为止,我想出了这个:

def parseSize(size):
    if size.endswith(" B"):
        size = int(size.rstrip(" B"))
    elif size.endswith(" KB"):
        size = float(size.rstrip(" KB")) * 1000
    elif size.endswith(" MB"):
        size = float(size.rstrip(" MB")) * 1000000
    elif size.endswith(" GB"):
        size = float(size.rstrip(" GB")) * 10000000000
    elif size.endswith(" TB"):
        size = float(size.rstrip(" TB")) * 10000000000000
    return int(size)

但我不喜欢它,而且我认为它不起作用。我只能找到做相反事情的模块。

【问题讨论】:

标签: python


【解决方案1】:

要回答 OP 的问题,似乎确实有一个模块,humanfriendly

pip install humanfriendly

那么,

>>> import humanfriendly
>>> user_input = raw_input("Enter a readable file size: ")
Enter a readable file size: 16G
>>> num_bytes = humanfriendly.parse_size(user_input)
>>> print num_bytes
16000000000
>>> print "You entered:", humanfriendly.format_size(num_bytes)
You entered: 16 GB
>>> print "You entered:", humanfriendly.format_size(num_bytes, binary=True)
You entered: 14.9 GiB

【讨论】:

    【解决方案2】:

    这是一个稍微漂亮一点的版本。这可能没有模块,只需定义内联函数。它非常小巧易读。

    units = {"B": 1, "KB": 10**3, "MB": 10**6, "GB": 10**9, "TB": 10**12}
    
    # Alternative unit definitions, notably used by Windows:
    # units = {"B": 1, "KB": 2**10, "MB": 2**20, "GB": 2**30, "TB": 2**40}
    
    def parse_size(size):
        number, unit = [string.strip() for string in size.split()]
        return int(float(number)*units[unit])
    
    
    example_strings = ["10.43 KB", "11 GB", "343.1 MB"]
    
    for example_string in example_strings:
        print(parse_size(example_string))
    
    10680
    11811160064
    359766426
    

    (请注意,不同的地方对 KB、MB 等的定义使用略有不同的约定——使用10**3 = 1000 的幂或2**10 = 1024 的幂。如果您的上下文是 Windows,您将希望使用后者. 如果你的上下文是 Mac OS,你会想要使用前者。)

    【讨论】:

    • 很好奇不要在这里和问题本身中使用 1024 作为乘数。
    • @mlissner 并非如此,因为 K 表示 1000,而 KB 在技术上是 1000 字节(其他前缀依此类推)。在实践中经常使用 1024,但从技术上讲,这将是一个 KiB,一个 Kibibyte。
    • 我想。不过,如果任何系统说某事是 5kb,我会认为这意味着 kibibyte。无论如何,希望这个讨论有一天能对某人有所帮助。这就是我真正追求的一切!
    • 我主要是想以一种有意义的方式对这些该死的东西进行排序,这很有效:)
    • 我们不要混淆/误导他人,坚持使用 2^n 位深度(KB 为 1024 等)。大多数开发者不知道 kibi/kilo、mega/medi 等之间的区别。
    【解决方案3】:

    我喜欢 Denziloe's answer 与 google 中出现的其他所有内容相比,但它

    • 数字和单位之间必须有空格
    • 不处理小写单位
    • 假设 kb 是 1000 而不是 1024,等等(感谢 mlissner 多年前试图指出这一点。也许我们的假设太老了,但我认为大多数软件都赶不上新的假设。)

    所以我把它调整成这样:

    import re
    
    # based on https://stackoverflow.com/a/42865957/2002471
    units = {"B": 1, "KB": 2**10, "MB": 2**20, "GB": 2**30, "TB": 2**40}
    
    def parse_size(size):
        size = size.upper()
        #print("parsing size ", size)
        if not re.match(r' ', size):
            size = re.sub(r'([KMGT]?B)', r' \1', size)
        number, unit = [string.strip() for string in size.split()]
        return int(float(number)*units[unit])
    
    example_strings = ["1024b", "10.43 KB", "11 GB", "343.1 MB", "10.43KB", "11GB", "343.1MB", "10.43 kb", "11 gb", "343.1 mb", "10.43kb", "11gb", "343.1mb"]
    
    for example_string in example_strings:
            print(example_string, parse_size(example_string))
    

    我们可以通过检查输出来验证:

    $ python humansize.py 
    ('1024b', 1024)
    ('10.43 KB', 10680)
    ('11 GB', 11811160064)
    ('343.1 MB', 359766425)
    ('10.43KB', 10680)
    ('11GB', 11811160064)
    ('343.1MB', 359766425)
    ('10.43 kb', 10680)
    ('11 gb', 11811160064)
    ('343.1 mb', 359766425)
    ('10.43kb', 10680)
    ('11gb', 11811160064)
    ('343.1mb', 359766425)
    

    【讨论】:

    • ? 使用2^n 位深度。
    【解决方案4】:

    根据chicks的回答,只用正则表达式解析大小,接受整数大小。

    UNITS = {None: 1, "B": 1, "KB": 2 ** 10, "MB": 2 ** 20, "GB": 2 ** 30, "TB": 2 ** 40}
    
    
    def parse_human_size(size):
        """
        >>> examples = [12345, "123214", "1024b", "10.43 KB", "11 GB", "343.1 MB", "10.43KB", "11GB", "343.1MB", "10.43 kb"]
        >>> for s in examples:
            print('[', s, ']', parse_human_size(s))
        """
        if isinstance(size, int):
            return size
        m = re.match(r'^(\d+(?:\.\d+)?)\s*([KMGT]?B)?$', size.upper())
        if m:
            number, unit = m.groups()
            return int(float(number) * UNITS[unit])
        raise ValueError("Invalid human size")
    

    【讨论】:

      【解决方案5】:

      代码搜索包含该字符串的度量单位。一旦发现。使用另一个正则表达式,提取数字。曾经做过这两件事。将值计算为字节。如果未指定该值,它会尝试将其视为字节,但如果无法转换,该函数将返回 0。

      def calculate(data):
      
          convertion={"G":1073741824,"M":1048576,"K":1024,"B":1}
          result=re.findall(r'G|M|K|B',data,re.IGNORECASE)
          if len(result)>=1:
              number=re.findall(r'[-+]?\d*\.\d+|\d+', data)
              number=float(number[0])
              return int(number*convertion[result[0].upper()])
          else:
            number=re.findall(r'[-+]?\d*\.\d+|\d+', data)
            if len(number)>=1:
              number=float(number[0])
              return int(number*convertion["B"])
            else:
                return 0
      

      【讨论】:

      • 你能编辑这个答案并解释代码的作用吗..?
      【解决方案6】:

      编辑:我错过了this other answer,它指出了另一个包humanfriendly,用于解决这个问题,而这个包只是为这种事情而构建的(而不是我建议从包中偷取实用程序函数)为完全不同的目的而建造)。所以 +1 这个答案。

      我最终来到这里是因为我想避免依赖,但对于那些不介意的人,您可以在 dask.utils.parse_bytes 中找到适合此的实用程序。

      import dask.utils
      # supports good range of human-readable units
      dask.utils.parse_bytes('150Gi')
      161061273600
      dask.utils.parse_bytes('150GB')
      150000000000
      # and potential spelling variants
      dask.utils.parse_bytes('150Gb')
      150000000000
      

      无论如何,here is the documentationhere is the source codeDask是python中的并行计算框架,来看看utils,留着并发:)

      【讨论】:

        猜你喜欢
        • 2013-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-12
        • 1970-01-01
        • 1970-01-01
        • 2013-02-06
        • 2013-02-17
        相关资源
        最近更新 更多