2011-08-18 152 views
3

我正在Arduino上開發一個項目,它解析來自遠程Web API的一些JSON數據,並在16x2 LCD上顯示它。如何在Arduino上格式化長添加千位分隔符

我想格式化一個長解析TextFinder添加千位分隔符(逗號分隔符將罰款)。

簡而言之,我該如何編寫formatLong函數?

long longToBeFormatted = 32432423; 

formattedLong = formatLong(longToBeFormatted); //How to implement this? 

lcd.print(formattedLong) // formattedLong is a string 

回答

4

我不確定在Arduino上使用了哪些工具集。有時候庫將支持非標準的「千人分組」標誌 - 單引號字符是典型的擴展:

printf("%'ld",long_val); 

如果你的庫不支持這一點,像下面這樣可能會做:

#include <stddef.h> 
#include <string.h> 
#include <limits.h> 
#include <stdio.h> 
#include <assert.h> 

size_t strlcpy(char* dest, char const* src, size_t dest_size); 

size_t format_long(long x, char* buf, size_t bufsize) 
{ 
    // This code assumes 32-bit long, is that the 
    // case on Arduino? Modifying it to be able to 
    // handle 64-bit longs (or to not care) should be 
    // pretty straightforward if that's necessary. 

    char scratch[sizeof("-2,147,483,648")]; 
    char* p = scratch + sizeof(scratch); // Work from end of buffer 
    int neg = (x < 0); 

    // Handle a couple special cases 
    if (x == 0) { 
     return strlcpy(buf, "0", bufsize); 
    } 
    if (x == INT_MIN) { 
     // Lazy way of handling this special case 
     return strlcpy(buf, "-2,147,483,648", bufsize); 
    } 

    // Work with positive values from here on 
    if (x < 0) x = -x; 

    int group_counter = 3; 
    *(--p) = 0; // Null terminate the scratch buffer 

    while (x != 0) { 
     int digit = x % 10; 
     x = x/10; 

     assert(p != &scratch[0]); 
     *(--p) = ""[digit]; 

     if ((x != 0) && (--group_counter == 0)) { 
      assert(p != &scratch[0]); 
      *(--p) = ','; 
      group_counter = 3; 
     } 
    } 

    if (neg) { 
     assert(p != &scratch[0]); 
     *(--p) = '-'; 
    } 
    return strlcpy(buf, p, bufsize); 
} 


/* 
    A non-optimal strlcpy() implementation that helps copying string 
    without danger of buffer overflow. 

    This is provided just in case you don't have an implementation 
    so the code above will actually compile and run. 
*/ 
size_t strlcpy(char* dest, char const* src, size_t dest_size) 
{ 
    size_t len = strlen(src); 

    if (dest_size == 0) { 
     // nothing to copy - just return how long the buffer should be 
     // (note that the return value doens't include the null terminator) 
     return len; 
    } 

    size_t tocopy = (dest_size <= len) ? dest_size-1 : len; 

    memmove(dest, src, tocopy); 
    dest[tocopy] = 0; 

    return len; 
} 
+0

試試用'final [final_pos--] = buffer [buff_pos - ]'來代替感謝您的幫助。分組不起作用,我也用gcc 4.0在本地Mac上嘗試過,但沒有成功,你知道關於該標誌的任何文檔嗎? 'format_long'函數很好用,不需要使用'strlcpy'本地函數。 Arduino上的長類型是32位的,所以你的功能非常適合。還有一個問題:爲什麼'format_long'函數需要'bufsize'參數? – systempuntoout

+0

我很喜歡讓調用者指定緩衝區大小,所以函數可以避免超出緩衝區的末端(這就是爲什麼我使用'strlcpy()')。另一種方法是讓函數動態分配所需大小的緩衝區並將其返回給調用者。但是在涉及像arduino這樣的小設備的項目中,動態內存通常不被使用。當然這取決於你的具體項目的要求。 –

+1

在這裏的GCC(實際上是libc)文檔中提到了千分組標誌:http://www.gnu.org/s/hello/manual/libc/Integer-Conversions.html#Integer-Conversions(但沒有非常詳細)。當然,你的arduino目標可能沒有完整的'libc'實現。 –

1

也許不是最好的算法,但這裏的一個實例(標準C):

char* formatLong(long toBeFormatted) 
{ 
    // Get the string representation as is 
    char* buffer = (char*) malloc(sizeof(long)); 
    ltoa(toBeFormatted, buffer, 10); 

    // Calculate how much commas there will be 
    unsigned int buff_length = strlen(buffer); 
    unsigned int num_commas = buff_length/3; 
    unsigned int digits_left = buff_length % 3; 
    if (digits_left == 0) 
    { 
     num_commas--; 
    } 

    // Allocate space for final string representation 
    unsigned int final_length = buff_length + num_commas + 1; 
    char* final = (char*) malloc(final_length); 
    memset(final, 0, final_length); 

    // Parse strings from last to first to count positions 
    int final_pos = final_length - 2; 
    int buff_pos = buff_length - 1; 
    int i = 0; 
    while(final_pos >= 0) 
    { 
     final[final_pos--] = buffer[buff_pos--]; 
     i++; 
     if (i % 3 == 0) 
     { 
      final[final_pos--] = ','; 
     } 
    } 

    // Free obsolete memory and return buffer 
    free(buffer); 
    return final; 
} 
+0

如果有人使用更短/更快的算法,請發佈它! – m0skit0

+0

我試過了,它似乎以某種方式工作。最後一位數字有問題;通過你的函數打印15195返回15,19ç,最後一個字符肯定是虛假的。 – systempuntoout

+0

在x86中正常工作。你可以用_memcpy()_... – m0skit0

0

你可以嘗試以下方法:

std::string formatLong(long l) { 
    int power = 0; 
    while (l/(pow(1000, power)) { power += 1; } 

    power -= 1; 

    std::stringstream s; 
    while (power) { 
     s << l/pow(1000, power); 
     s << ","; 
     l % (pow(1000, power)); 
     power -= 1; 
    } 
    return s->str(); 
} 

的代碼是從臀部射擊,但這個想法應該起作用。