2012-11-12 39 views
8

मुझे स्ट्रिंग्स को कन्वर्ट करने की आवश्यकता है जिसमें बाइट्स में मेमोरी उपयोग होता है, जैसे: 1048576 (जो 1 एम है) बिल्कुल, एक मानव-पठनीय संस्करण, और वीजा-विपरीत।मानव पठनीय, और पीछे बाइट्स। डेटा हानि के बिना

नोट: मैं यहाँ पहले से ही देखा: Reusable library to get human readable version of file size?

और यहाँ (भले ही यह अजगर नहीं है): How to convert human readable memory size into bytes?

कुछ भी नहीं अब तक मुझे मदद की, तो मैं कहीं और देखा।

मैं कुछ है कि मेरे लिए यह करता है यहाँ पाया है: http://code.google.com/p/pyftpdlib/source/browse/trunk/test/bench.py?spec=svn984&r=984#137 या, अपेक्षाकृत छोटे URL के लिए: http://goo.gl/zeJZl

कोड:

def bytes2human(n, format="%(value)i%(symbol)s"): 
    """ 
    >>> bytes2human(10000) 
    '9K' 
    >>> bytes2human(100001221) 
    '95M' 
    """ 
    symbols = ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') 
    prefix = {} 
    for i, s in enumerate(symbols[1:]): 
     prefix[s] = 1 << (i+1)*10 
    for symbol in reversed(symbols[1:]): 
     if n >= prefix[symbol]: 
      value = float(n)/prefix[symbol] 
      return format % locals() 
    return format % dict(symbol=symbols[0], value=n) 

और यह भी रूपांतरण के लिए एक समारोह अन्य तरीके से (एक ही साइट) :

def human2bytes(s): 
    """ 
    >>> human2bytes('1M') 
    1048576 
    >>> human2bytes('1G') 
    1073741824 
    """ 
    symbols = ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') 
    letter = s[-1:].strip().upper() 
    num = s[:-1] 
    assert num.isdigit() and letter in symbols 
    num = float(num) 
    prefix = {symbols[0]:1} 
    for i, s in enumerate(symbols[1:]): 
     prefix[s] = 1 << (i+1)*10 
    return int(num * prefix[letter]) 

यह बहुत अच्छा है और सभी, लेकिन यह कुछ जानकारी की कमी, उदाहरण है:

>>> bytes2human(10000) 
'9K' 
>>> human2bytes('9K') 
9216 

इस हल करने का प्रयास करने के लिए, मैं समारोह bytes2human

में पर स्वरूप को: format="%(value).3f%(symbol)s")

कौन ज्यादा अच्छा है, मुझे इन परिणाम दे:

>>> bytes2human(10000) 
'9.766K' 

लेकिन जब मैं उन्हें human2bytes फ़ंक्शन के साथ वापस बदलने की कोशिश करता हूं:

>>> human2bytes('9.766K') 

Traceback (most recent call last): 
    File "<pyshell#366>", line 1, in <module> 
    human2bytes('9.766K') 
    File "<pyshell#359>", line 12, in human2bytes 
    assert num.isdigit() and letter in symbols 
AssertionError 

यह .

की वजह से है तो मेरे सवाल है, मैं कैसे एक मानव पठनीय संस्करण वापस बाइट-संस्करण में बदल सकते हैं, बिना डेटा के नुकसान?

नोट: मुझे पता है कि 3 दशमलव स्थानों भी डेटा हानि का एक छोटा सा है। लेकिन इस सवाल के प्रयोजनों के लिए, अब अनदेखा करते हैं कि अब मैं इसे किसी और चीज़ में बदल सकता हूं।

उत्तर

5

तो यह पता चला है इस सवाल का जवाब बहुत सरल से मैंने सोचा था - लिंक है कि मैं वास्तव function का एक बहुत अधिक विस्तृत संस्करण के लिए नेतृत्व किया, बशर्ते में से एक:

जो किसी भी गुंजाइश मैं दे के साथ सौदा करने में सक्षम है यह।

लेकिन आपकी मदद के लिए धन्यवाद:

कोड यहाँ भावी पीढ़ी के लिए कॉपी किया:

## {{{ http://code.activestate.com/recipes/578019/ (r15) 
#!/usr/bin/env python 

""" 
Bytes-to-human/human-to-bytes converter. 
Based on: http://goo.gl/kTQMs 
Working with Python 2.x and 3.x. 

Author: Giampaolo Rodola' <g.rodola [AT] gmail [DOT] com> 
License: MIT 
""" 

# see: http://goo.gl/kTQMs 
SYMBOLS = { 
    'customary'  : ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'), 
    'customary_ext' : ('byte', 'kilo', 'mega', 'giga', 'tera', 'peta', 'exa', 
         'zetta', 'iotta'), 
    'iec'   : ('Bi', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'), 
    'iec_ext'  : ('byte', 'kibi', 'mebi', 'gibi', 'tebi', 'pebi', 'exbi', 
         'zebi', 'yobi'), 
} 

def bytes2human(n, format='%(value).1f %(symbol)s', symbols='customary'): 
    """ 
    Convert n bytes into a human readable string based on format. 
    symbols can be either "customary", "customary_ext", "iec" or "iec_ext", 
    see: http://goo.gl/kTQMs 

     >>> bytes2human(0) 
     '0.0 B' 
     >>> bytes2human(0.9) 
     '0.0 B' 
     >>> bytes2human(1) 
     '1.0 B' 
     >>> bytes2human(1.9) 
     '1.0 B' 
     >>> bytes2human(1024) 
     '1.0 K' 
     >>> bytes2human(1048576) 
     '1.0 M' 
     >>> bytes2human(1099511627776127398123789121) 
     '909.5 Y' 

     >>> bytes2human(9856, symbols="customary") 
     '9.6 K' 
     >>> bytes2human(9856, symbols="customary_ext") 
     '9.6 kilo' 
     >>> bytes2human(9856, symbols="iec") 
     '9.6 Ki' 
     >>> bytes2human(9856, symbols="iec_ext") 
     '9.6 kibi' 

     >>> bytes2human(10000, "%(value).1f %(symbol)s/sec") 
     '9.8 K/sec' 

     >>> # precision can be adjusted by playing with %f operator 
     >>> bytes2human(10000, format="%(value).5f %(symbol)s") 
     '9.76562 K' 
    """ 
    n = int(n) 
    if n < 0: 
     raise ValueError("n < 0") 
    symbols = SYMBOLS[symbols] 
    prefix = {} 
    for i, s in enumerate(symbols[1:]): 
     prefix[s] = 1 << (i+1)*10 
    for symbol in reversed(symbols[1:]): 
     if n >= prefix[symbol]: 
      value = float(n)/prefix[symbol] 
      return format % locals() 
    return format % dict(symbol=symbols[0], value=n) 

def human2bytes(s): 
    """ 
    Attempts to guess the string format based on default symbols 
    set and return the corresponding bytes as an integer. 
    When unable to recognize the format ValueError is raised. 

     >>> human2bytes('0 B') 
     0 
     >>> human2bytes('1 K') 
     1024 
     >>> human2bytes('1 M') 
     1048576 
     >>> human2bytes('1 Gi') 
     1073741824 
     >>> human2bytes('1 tera') 
     1099511627776 

     >>> human2bytes('0.5kilo') 
     512 
     >>> human2bytes('0.1 byte') 
     0 
     >>> human2bytes('1 k') # k is an alias for K 
     1024 
     >>> human2bytes('12 foo') 
     Traceback (most recent call last): 
      ... 
     ValueError: can't interpret '12 foo' 
    """ 
    init = s 
    num = "" 
    while s and s[0:1].isdigit() or s[0:1] == '.': 
     num += s[0] 
     s = s[1:] 
    num = float(num) 
    letter = s.strip() 
    for name, sset in SYMBOLS.items(): 
     if letter in sset: 
      break 
    else: 
     if letter == 'k': 
      # treat 'k' as an alias for 'K' as per: http://goo.gl/kTQMs 
      sset = SYMBOLS['customary'] 
      letter = letter.upper() 
     else: 
      raise ValueError("can't interpret %r" % init) 
    prefix = {sset[0]:1} 
    for i, s in enumerate(sset[1:]): 
     prefix[s] = 1 << (i+1)*10 
    return int(num * prefix[letter]) 


if __name__ == "__main__": 
    import doctest 
    doctest.testmod() 
## end of http://code.activestate.com/recipes/578019/ }}} 
4

आप अपने आखिरी नोट में अपने स्वयं के प्रश्न का उत्तर दे रहे हैं।

human2bytes(s) में, उदाहरण के लिए इनपुट स्ट्रिंग - 9.766K - दो भागों, संख्या और उपसर्ग में विभाजित है। दावे के बाद (जिसे आप सही तरीके से देखते हैं वह त्रुटि को फेंकता है), संख्या को संबंधित मान से गुणा किया जाता है जो उपसर्ग का प्रतिनिधित्व करता है, इसलिए 9.766 * 1000 = 9766। डेटा हानि से बचने का एकमात्र तरीका इनपुट के रूप में पर्याप्त सटीक फ़्लोटिंग-पॉइंट मान को स्वीकार करना है।

आदेश human2bytes फ्लोटिंग प्वाइंट इनपुट स्वीकार करने के लिए, आप या तो जोर से num.isdigit() को दूर कर सकता है और उसके बाद से कोशिश को छोड़कर, या check it by some other means typecasting num = float(num) लपेट दें।

+0

+1 सटीक फ़्लोटिंग-बिंदु मान के बारे में बात की परवरिश के लिए। आप मूल रूप से दोनों के बीच एक सममित अनुवाद नहीं कर सकते - मानव पठनीय रूप अल्पसंख्यक के लिए मूल्यों को कम कर देता है। – synthesizerpatel