숫자에 세자리마다 콤마찍는 함수 최적화
글쓴이: saxboy / 작성시간: 월, 2004/07/26 - 9:19오후
요 며칠 외주로 하는 일 하나에서 마무리 단계에 숫자에 세자리마다 콤마를 찍어달라고 하더군요. 별 생각 없이 만들다가 문득 재미있겠다는 생각이 들어 올려봅니다.
방법 1.
3으로 몫과 나머지를 구하고 나머지부분을 먼저 strcpy, 이후 몫만큼 루프를 돌면서 strcpy & 콤마 찍기
그런데, 코드를 만들려고 생각하니 참 일관성이 없더군요. 다시 다른 방법을 생각해보았습니다.
방법 2. 스트링 마지막부터 하나씩 카피하면서 3자리마다 콤마넣어주기.
이렇게 생각해보니 첫번째 아이디어보다는 웬지 깔끔해지더군요. 이렇게 만든 함수가 요놈입니다.
int util_add_comma_to_num(const char *str, char *buf, int buflen)
{
int len=0;
int num_commas=0;
int comma_count=0;
int i=0;
int n=0;
/* count given string */
len = strlen(str);
num_commas = (int)(len/3);
assert( buflen >= (len + num_commas +1));
buf[len + num_commas] = '\0';
for (i=len-1, n=1; i>=0; i--, n++)
{
buf[i + num_commas - comma_count] = str[i];
if ( (n%3)==0 )
{
comma_count++;
buf[i + num_commas - comma_count] = ',';
}
}
}
#ifdef __TEST__
int main(int argc, char **argv)
{
char buf[1024]={0,};
util_add_comma_to_num("12345678000", buf, 1024);
printf("%s\n", buf);
}
#endif
굉장히 간단한 코드인데, 역시나 스트링처리이다보니 귀찮은 일이 생기고, 구현 여하에 따라서 웬지 위에 적은 것은 비교도 되지 않을 정도로 깔끔하게 만들 수 있겠다는 느낌이 얼핏들더군요. 다른 분들은 어떻게 만드실지 무척 궁금해져서 스레드를 하나 만들어봅니다. 다른 아이디어 또는 깔끔한 구현! 당신의 능력을 보여주세요.
ps. 웬지 recursive로 만들어도 재미있겠다는 생각이 듭니다.


댓글
http://bbs.python.or.kr/viewtopic.php?t=
http://bbs.python.or.kr/viewtopic.php?t=20504
예전에 본 기억이 있어서 링크를 남겨봅니다. ^^;
위 프로그램은 문자열 길이가 3의 배수일 경우 잘못 동작합니다. :(
위 프로그램은 문자열 길이가 3의 배수일 경우 잘못 동작합니다. :(
그리고 굳이 뒤에서부터 복사할 필요 있나요?
int util_add_comma_to_num(const char *str, char *buf, int buflen) { int len; int shift; /* count given string */ len = strlen(str); shift = -len; assert( buflen >= (len + len/3 +1)); while (*str) { *buf++ = *str++; if (++shift && (shift % 3) == 0) *buf++= ','; } *buf = '\0'; return 0; }사족: "토론, 토의"보다는 그냥 "프로그래밍 Q&A" 쪽에 올리셨어도...
와~ 굉장한
와~
굉장한 고수이시네요~
^^__^^ 나도 언제묜???
좋은 하루 되세요!!
[quote]위 프로그램은 문자열 길이가 3의 배수일 경우 잘못 동작합니
아유... 창피... :oops:
조금전에 생각하면서는 웬지 뒤부터 복사를 하면 참 깔끔해진다고 생각했는데, 다시 보니 그렇지도 않군요. shift가 참 멋진 것 같아요.
웬지 퍼즐같은 기분이라 토론쪽에 올려두었는데, 별로 적절하지 않을까요? 그렇다면 관리자님께서 옮겨주시면 좋겠습니다.
숫자에 세자리마다 콤마찍는 함수 최적화
예전에 어디선가 본 Duff's device 라는 것이 생각나서... 8)
int util_add_comma_to_num2(const char *str, char *buf, int buflen) { int len, src, dst; len=strlen(str); src = 0; dst = 0; assert(len > 0); if (len <= 0) return -1; assert(buflen >= len + ((len - 1) / 3) + 1); if (buflen < len + ((len - 1) / 3) + 1) return -1; switch ((len + 2) % 3) { while (src < len) { buf[dst++] = ','; case 2: buf[dst++] = str[src++]; case 1: buf[dst++] = str[src++]; case 0: buf[dst++] = str[src++]; } } buf[dst++] = '\0'; return 0; }while loop 내부로의 (goto) switch라.. 상당히 맘에
while loop 내부로의 (goto) switch라.. 상당히 맘에 안 드는 코드로군요. :)
[quote="cdpark"][code:1]intutil_add_co
피연산자가 음수일때 % 연산 결과는 기계마다 다르다고 봤는데...
제가 옛날 책을 보고 있는 건가요??
[code:1]int util_add_comma_to_num(
int util_add_comma_to_num(const char *str, char *buf, int buflen) { int i = 0; int pos = 0; assert(buflen >= ((strlen(str) * 4) / 3 + 1)); memset(buf, 0, buflen); pos = strlen(str) % 3; strncpy(buf, str, pos); for (i = pos; i < strlen(str); i+=3) { if (i > 0) strcat(buf, ","); strncat(buf, str + i, 3); } return 0; }이건 어떨까요?
[quote="eplus2"]피연산자가 음수일때 % 연산 결과는 기계마다
-2 % 3 에 대해 1을 돌려줄 수도 있고, -2를 돌려줄 수도 있으니깐요. 하지만 -3 % 3 에 대해서는 0을 돌려주겠죠? (면피!)
cdpark님 버전을 약간더 줄여봤습니다.[code:1]/*
cdpark님 버전을 약간더 줄여봤습니다.
/* * Put a comma after every 3 digit. * * buf must be large enough to hold a result string. */ void clarify_number(const char *str, char *buf) { int len; len = strlen(str); assert(len > 0); while (*str) { *buf++ = *str++; if (--len && (len % 3) == 0) *buf++= ','; } *buf = '\0'; }한국 BSD 사용자 포럼
최적화란 쓸데없는 계산을 빼는 것.
int util_add_comma_to_num (const char *str, char *buf, int buflen) { int len; len = strlen(str); assert(buflen >= (len + len/3 + 1)); switch (len % 3) { case 2: *buf++ = *str++; case 1: *buf++ = *str++; case 0: break; } for (;*str;) { *buf++ = ','; *buf++ = *str++; *buf++ = *str++; *buf++ = *str++; } *buf = '\0'; return 0; }arith님의 코드는 112,1231,23412,3
arith님의 코드는
1
12
,123
1,234
12,345
,123,456
1,234,567
12,345,678
,123,456,789
와 같은 결과를 내는군요.
한국 BSD 사용자 포럼
[quote="방준영"]cdpark님 버전을 약간더 줄여봤습니다.
좀 더 줄여 볼까요?
void clarify_number(const char *str, char *buf) { int len; len = strlen(str); assert(len > 0); while ( (*buf++ = *str++) ) { if (--len && (len % 3) == 0) *buf++= ','; } *buf = '\0'; }---
http://coolengineer.com
Duff 가 누구에요?
위의 Duff's device 스타일의 코드를 다시 좀 더 짧고 보기 좋게 (?) 써 봤습니다. switch () 문의 브레이스도 생략이 가능하다는군요!
void util_add_comma_to_num2(const char *str, char *buf, int buflen) { int len = strlen(str); assert(len > 0); assert(buflen >= len + ((len - 1) / 3) + 1); switch ((len - 1) % 3) while (*str) { *buf++ = ','; case 2: *buf++ = *str++; case 1: *buf++ = *str++; case 0: *buf++ = *str++; } *buf++ = '\0'; }방준영님이나 pynoos 님 버전 정도라면 strcpy() 와 꽤나 비슷
방준영님이나 pynoos 님 버전 정도라면 strcpy() 와 꽤나 비슷해져서, 아예 strcpy() 에 맞춰 argument 순서와 반환 타입을 바꿔 봤습니다. 그 외에 사소한 차이점이 좀 더 있습니다. :)
char * clarify_number(char *buf, const char *str) { char *saved = buf; size_t len = strlen(str); while ((*buf++ = *str++) != '\0') if (--len && (len % 3) == 0) *buf++ = ','; return saved; }p.s. 개인적으로는 중간에 쓸데없는 비교를 더 이상 하지 않는 Duff's device 쪽이 마음에 듭니다. 물론 코드가 더 괴상하긴 하지만요. :)
[code:1]int util_add_comma_to_num (c
int util_add_comma_to_num (const char *str, char *buf, int buflen) { int len; if (!*str) { *str = '\0'; return 0; } len = strlen(str); assert(buflen >= (len + len/3 + 1)); switch (len % 3) { case 0: *buf++ = *str++; case 2: *buf++ = *str++; case 1: *buf++ = *str++; } while (*str) { *buf++ = ','; *buf++ = *str++; *buf++ = *str++; *buf++ = *str++; } *buf = '\0'; return 0; }arith 님의 코드가 맘에 드네요. 버그가 있으면 잡으면 되죠.
조금더 고쳐서 0으로 시작, 앞뒤 공백, +/- 부호 까지 처리하게 ^^
조금더 고쳐서 0으로 시작, 앞뒤 공백, +/- 부호 까지 처리하게 ^^;
char * clarify_number(char *str, char *buf) { int len; char *p; if (*str == '\0') { *buf = '\0'; return((char *)NULL); } /* strip space backward */ p = str + strlen(str) - 1; for ( ; *p == ' ' ; p--) ; *(++p) = '\0'; /* strip space forward */ for ( ; *str == ' ' || *str == '0'; str++) ; p = buf; if (*str == '+') *str++; if (*str == '-') *buf++ = *str++; if ((len = strlen(str)) <= 0) { *buf = '\0'; return((char *)NULL); } while ( (*buf++ = *str++) ) { if (--len && (len % 3) == 0) *buf++= ','; } *buf = '\0'; return(p); }>/dev/null 2>&1
C++로 해봤습니다. :D [code:1]#include <i
C++로 해봤습니다. :D
#include <iostream> #include <string> using std::string; void insert_separator(string& s, char separator = ',', int width = 3) { string::iterator i = s.end() - width; while (i > s.begin()) i = s.insert(i, separator) - width; } int main() { string s("123456789"); insert_separator(s); std::cout << s << std::endl; }소수점이하도 처리하실 분? ;)
소수점이하도 처리하실 분? ;)
---
http://coolengineer.com
[code:1]int util_add_comma_to_num(
int util_add_comma_to_num(const char *str, char *buf, int buflen) { int w=0, i=0; int len=0; len = strlen(str); w = len %3; w = w ? w : 3; for (i=0; i<w; i++) *buf++ = *str++; if ( len <3 ) return 1; else { if ( len>3) *buf++=','; return util_add_comma_to_num( str, buf, buflen-w ); } return 1; }꼬리에 덧붙여놓았던 recursive 버전 하나 만들어봅니다.
cdpark님의 것을 제가 수정한 것을 pynoos님이 수정한 것을 다시
cdpark님의 것을 제가 수정한 것을 pynoos님이 수정한 것을 다시 수정한 버전. 마지막에 붙는 buf = '\0';를 삭제했습니다.
void clarify_number(const char *str, char *buf) { int len; len = strlen(str); assert(len > 0); while (*buf++ = *str++) { if (--len && (len % 3) == 0) *buf++= ','; } }Duf's device(?) 코드를 경고 안나게 수정한 버전.
void util_add_comma_to_num2(const char *str, char *buf, int buflen) { int len = strlen(str); assert(len > 0); assert(buflen >= len + ((len - 1) / 3) + 1); switch ((len - 1) % 3) { case 3: /* fake label to make gcc happy */ while (*str) { *buf++ = ','; case 2: *buf++ = *str++; case 1: *buf++ = *str++; case 0: *buf++ = *str++; } } *buf = '\0'; }한국 BSD 사용자 포럼
cdpark님 버전을 조금 더 줄여보았습니다.[code:1]v
cdpark님 버전을 조금 더 줄여보았습니다.
void clarify_number(const char *str, char *buf) { while (*buf++ = *str++) { if ((strlen(str) % 3) == 0) *buf++= (*str ? ',' : '\0'); } }좀 더 정확히 얘기하자면
cdpark님 -> 방준영님 -> pynoos님 으로 수정된 버전이지요...
성능은 어떻게 될까요? 무조건 라인수 적다고 빠른건 아니겠죠?[c
성능은 어떻게 될까요? 무조건 라인수 적다고 빠른건 아니겠죠?
void util_add_comma_to_num2(const char *str, char *buf, int buflen) { int len; len = strlen(str); while(*buf++ = *str++) if( --len && !(len % 3) ) *buf++ = ','; }제가 초보라, 언뜻 보기엔 이게 젤 빠를것 같은데 아닌가요?
(안전성은 고려하지 않구요)
언제나 시작
arith 님의 코드를 제가 고친 버젼, 혹은 Duff's device를
arith 님의 코드를 제가 고친 버젼, 혹은 Duff's device를 쓴 버젼(결국 둘은 같습니다.) 등이 가장 빠를겁니다.
컴파일러의 최적화 루틴은 소스가 긴 편을 선호하므로 제가 고친 버젼을 좋아할거라고 주장합니다. :)
pentium 4의 깊은 파이프라인을 위해서는 loop를 더 풀어야할지도 모르고요. :)
Duff's device가 뭔가 해서 찾아봤더니 이런 것이었군요.ht
Duff's device가 뭔가 해서 찾아봤더니 이런 것이었군요.
http://info.astrian.net/jargon/terms/d/Duff_s_device.html
정말 멋진 아이디어입니다. 그런데 저만 몰랐나요... :wink:
한국 BSD 사용자 포럼
java 버전...
예전에 만들어 둔것이 있었내요.. :)
//세자리마다 컴마찍기//////////////////////////////////////////////////////////////////////////// public String NumberProc(int num){ String srcString = Integer.toString(num); int len = srcString.length(); resultNumber = ""; if(len > 3){ if(len%3 != 0){ resultNumber = resultNumber + srcString.substring(0,len%3)+","; } srcString = srcString.substring(len%3); len = srcString.length(); while(len > 3){ resultNumber = resultNumber + srcString.substring(0,3)+","; srcString = srcString.substring(3); len = srcString.length(); } resultNumber = resultNumber + srcString; } else{ // 세자리수보다 작다 return srcString; } return this.resultNumber; }멋진남자...
Re: java 버전...
자바는 JDK에서 지원할 텐데 굳이 만드실 필요는... :?
Re: java 버전...
할줄아는건 c 뿐이고..
자바로 만들라하니...
위와같은 코드가 나오내요...
자바 너무 어려워요...
멋진남자...
[quote="doldori"]C++로 해봤습니다. :D [/quote
ANSI C++도 Java 처럼 천단위 컴마 찍기를 지원합니다.
표준 라이브러리의 locale 클래스를 사용하면 되지요.
std::string sep_thousands(double f) { using namespace std; const char *locale_name = #ifdef WINDOWS "korean"; #endif ostringstream oss; oss.imbue(locale(locale_name)); oss << f; return oss.str(); }로케일을 한국어나 영어로 설정하면 자동으로 천단위 컴마 찍기가 됩니다.
(소숫점 이하는 찍히지 않습니다.)
만약 독일어로 설정하면 컴마(,) 대신 피리어드(.)가 찍히죠.
ANSI C에서도 로케일을 써서 이렇게 할 수 있는 지는 모르겠습니다.
제가 C는 잘 몰라서요. :oops:
[quote="cedar"][quote="doldori"]C++로 해봤습
음.. 제가 한번 해봤는데. 안되는데.. 왜 안되는거죠?
#include <iostream> #include <string> #include <sstream> using namespace std; std::string sep_thousands(double f) { using namespace std; const char *locale_name = #ifdef WINDOWS "korean"; #else "ko_KR"; #endif ostringstream oss; oss.imbue(locale(locale_name)); oss << f; return oss.str(); } int main() { cout << sep_thousands(100000) << endl; return 0; } 결과 100000ko_KR를 ko-KR, korea 모두 바꾸어 봐도 안돼는군요..
LINUX 환경입니다.
고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"
In Perl...1. CPAN에서
In Perl...
1. CPAN에서 Tie::Comma 모듈 설치
2. Tie::Comma 패키지가 Export하는 %comma 변수를 사용해서 숫자 변환
3. 음수 소수점 상관없이 동작
#!/usr/bin/perl use Tie::Comma; my $a = 1234567.89; print "With commas: $comma{$a}\n";---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!
Kim Do-Hyoung Keedi
----
use perl;
Keedi Kim
Perl 정규식으로
sub commify { my $text = reverse $_[0]; #숫자를 역으로 $text =~ s/ (\d{3}) #3개의 연속된 숫자 (?=\d) #그다음에 숫자가나오는(lookaheads) (?!\d*\.)#소숫점 이하부문은 무시(lokkbehinds) /$1,/gx; return scalar reverse $text; }이렇게 구현도 가능해요^^
Gema로 구현하면 ...
--------
설명
<D1> 은 1자리 숫자
<D2> 는 2자리 숫자
<D3> 은 세자리 숫자
<D> 는 자릿수 관계없이 연속된 숫자
모든숫자는 , 찍는 관점에서 보면 3종류로 나누어진다
첫번째는
1,234
1,234,456
처럼 처음의 , 나오기전에 숫자가 1개인것
두번째는
12,345
12,344,567
처럼 처음의 , 나오기전에 숫자가 2개인것
그리고 마지막으로
123,456
123,456,789
처럼 처음의 , 나오기전에 숫자가 3개인것
그리고 처음 콤마를 포함한 뒷자리는 , 와 3자리 숫자의 반복이다.
<CDR> 은 이 3자리 숫자의 반복을 패턴으로잡아내어 그 사이에 , 를 붙인다.
<CDR> 은 어떻게 3자리 숫자를 찾는가?
CDR 은 3개의 룰로 구성되어있는데
첫번째는
<D3>=,$1
3자리 숫자를 만나면 숫자앞에 , 를 붙인다.
두번째는
<D>=@fail
숫자를 만나면 지금 처리하는 문자는 CDR 패턴에 맞지 않는다라고 알려준다.
세번째는
=@end
성공적으로 처리를 끝낸다. (지금 처리한 문자열은 CDR 패턴이다.)
12345678 을 변화하는 예를 들면
맨처음 <D1><CDR>에 12345678 이 맞는지 비교한다.
<D1>=1
<CDR>=2345678 이어야 패턴에 맞는데
CDR 에 2345678 을 매칭시켜보면
(룰 적용 순서는 먼저정의된 룰먼저 적용하고 룰이 적용되면 이후 스트링은 룰의 처음부터 다시적용된다)
CDR 의 처음룰에 의해 234 이 ,234 으로 변화되고
나머지 45678 에 대해서
CDR 룰의 처음부터 다시적용하면 567 이 ,567 으로 변환되고
룰이 적용되었으니 나머지 8 에 대해 CDR 룰의 처음부터 다시적용하면
첫번째 룰은 3자리수 이어야 하는데 남은것은 8 하나이니 첫번째 룰은 실패
두번째 룰을 적용하면 숫자일경우 @fail 인데 8은 숫자이므로 여지껏 변환한거 롤백함 실패응 돌려줌
다시 처음으로 돌아와서
결국 <D1><CDR> 패턴이 CDR 에서 실패함으로써 결국 맞지않았으므로
12345678 을 두번째 룰 <D2><CDR>을 적용해 본다.
그러면 아까와 같은 방법으로 <D2> 에 해당하는 12 를 제외한 345678 을 <CDR> 에 적용해보면
CDR 의 첫번째 패턴이 두번적용되면 세번째 적용할때 CDR 의 세번째 룰 =@end 에 의해 성공적으로 매칭이 끝난다.
그러면 <D2><CDR>=$1$2 에 의해 D2 -> 12 CDR -> ,345,678 로 치환된다.
-------------------------------------------------------------------
그리고... Gema 쓰시는분 어디 없나요?
빠르지만 않지만 짧은 Haskell 버전
간단하죠?
제가 쓰는 java버전...
import java.text.DecimalFormat; // 숫자를 원하는 형식으로 바꿔 문자열로 바꿔주는 API
import java.io.*;
public class Money
{
public static void main(String args[]) throws IOException
{
...... 변수명들 생략 ......
String checkDay = null;
String checkMoney = null;
....입력받은 것이 숫자인지 체크하는 부분 생략......
checkDay = new DecimalFormat("#,###").format(y);
checkMoney = new DecimalFormat("#,###").format(saveMoney);
......중간 왕창생략..^^......
}
이런식으로 사용중입니다. 변수명 'y'에는 날짜를 받아와서 '1,234' 일... 이런식으로 찍어주고 'saveMoney'에는 누적된 합계금액을 써서 '1,234,856' 원... 이럭식으로 콤마를 찍어주고 있죠. 원래 예전 쓰레드에 글 올린적이 있는 하루에 10원씩 늘여가면서(첫날 10원, 둘째날 20원 이런식...) 저금하면 키보드로 입력받은 날짜의 누적금액은 얼마인가하는 호기심에 15분간에 걸쳐 뚝딱거려 만든 소스중 일부였죠.^^
예전 1.3때는 만들어 썼는데 1.4때부터 DecimalFormat 로 사용하니 편하더라구요.^^
-------------------------------------------------------------------------------------------
나에겐 할 수 있다는 의지와
하면 된다는 신념과
해야 한다는 의무가 있다.
http://rx78gd.egloos.com
-------------------------------------------------------------------------------------------
나에겐 할 수 있다는 의지와
하면 된다는 신념과
해야 한다는 의무가 있다.
http://rx78gd.tistory.com
Duff's device 코드와 제 코드가 거의 똑같네요.
몇달전에 봤던 한글과컴퓨터 면접 실기테스트 3번문제였던가. 이 문제였습니다.
> -100000
>> -100,000
> +1000000
>> +1,000,000
> 100000
>> 100,000
신기하네요. 랭귀지가 같은 이상 길은 하나인가. 매번 느끼는거지만. 모든 길은 로마로 통한다!!
제 개인적인 생각으로 루핑을 푸는것도 중요하지만, 루프안의 조건문을 최대한 줄이는거죠.
루프안의 조건문은 최적화를 방해하는 요소인듯 합니다.
이 문제 특성상 플밍스킬이 조그만 있어도 쉽게 풀수 있지만. 루프->조건
조금 생각해보면 루프안의 조건을 쉽게 풀수 있습니다.
Hello World.
파일정리하다 찾았네요.
작년에 한글과컴퓨터 면접용 1번문제였네요. 그 당시 컴이 갑자기 맛이가서리 하루밖에 시간이 없어서 6문제중 5문제만 풀어서 제출했는데 나중에 문서를 잘 일어보니까. 한문제당 20점 총 120점, 100점이하는 무조건 탈락. ㅡㅡ;
결국 5문제를 만점 받아도 한문제라도 못풀면 자동탈락이었다는..ㅋㅋㅋ
주석이 빠진걸 보니까. 최종 제출본은 아니었네요. 찾으면 다시 수정하겠씁니다.
#define CIPER (float)(3.0)
#define MAGIC_NUMBER (float)(0.7)
두 값을 수정하면 자릿수 변경이 가능합니다,
지금와서 보니 위의 더프의 디바이스와 거의 비슷하죠!? ^^; 이런 사실을 소스 냈을때 한컴팀장들은 알았으라나..ㅋㅋㅋ
#include "stdio.h" #include "stdlib.h" #include "assert.h" #include "string.h" #include "ctype.h" /* */ #define MAX_BUFFER (32) #define MAX_INPUT (MAX_BUFFER - (1)) #define PLUS '+' #define MINUS '-' #define CIPER (float)(3.0) #define MAGIC_NUMBER (float)(0.7) /* */ typedef enum { SUCCEEDED = 0, FAILED = -1 } ERROR; /* */ ERROR init( char* ); ERROR release( char* ); ERROR expr_check( const char* ); ERROR input( char*, unsigned int ); ERROR separate_currency( char* , const char* ); ERROR _reverse_string( char* , const char*, int ); int main( int argc, char* argv[] ) { char input_buf[MAX_BUFFER]; char result_buf[MAX_BUFFER]; init( input_buf ); init( result_buf ); input( input_buf, MAX_INPUT ); if( expr_check( input_buf ) == FAILED ) { perror( "expression error." ); return -1; } if( separate_currency( result_buf, input_buf ) == FAILED ) { perror( "currency convert error." ); return -1; } puts( result_buf ); release( result_buf ); release( input_buf ); return 0; } /* */ ERROR separate_currency( char* dest, const char* src ) { int length = 0; int comma_count = 0; int expr_signed = 0; int i = 0; int tmp_val = 0; assert( NULL != dest && NULL != src ); length = strlen( src ); assert( 0 < length ); /* strlen() contain '\0' */ length--; /* signed '-', '+' */ if( '-' == *src || '+' == *src ) expr_signed = 1; /* ex) -123567 ( ( 4 - 1 ) / 3.0 ) + 0.7 - 1 */ comma_count = ( ( ( length - expr_signed ) / CIPER ) + MAGIC_NUMBER ) - 1; /* ex) (-123),567 4 = 7 - ( 1 * 3 ) */ tmp_val = length - ( comma_count * 3 ); while( 0 < tmp_val-- ) { *dest++ = *src++; } while( 0 < comma_count-- ) { *dest++ = ','; *dest++ = *src++; *dest++ = *src++; *dest++ = *src++; } return SUCCEEDED; } /* */ ERROR _reverse_string( char* dest , const char* src, int length ) { assert( NULL != dest && NULL != src ); assert( 0 < length ); /* strlen() contain '\0' */ length--; /* base + off */ src += length; while( 0 <= length-- ) { *dest++ = *src--; } return SUCCEEDED; } /* */ ERROR expr_check( const char* str ) { char* dummy = NULL; char* tmp = NULL; size_t len = 0; int i = 0; ERROR err = SUCCEEDED; assert( NULL != str ); len = strlen( str ); assert( len > 0 ); tmp = (void*) malloc ( sizeof(char) * len ); assert( NULL != tmp ); memset ( tmp, 0, sizeof(char) * len ); dummy = strncpy( tmp, str, len - 1 ); assert( dummy == tmp ); /* signed check */ if( !isdigit(*dummy) && PLUS != *dummy && MINUS != *dummy ) err = FAILED; /* optimize zone - casting (void*)*(++dummy) -, Macro, Assemble */ while( NULL != *(++dummy) ) { /* 58 -> 127 = 69 ( alphabet ), 0 -> 47 = 48 ( specail )*/ if( *dummy > '9' || '0' > *dummy ) err = FAILED; } memset ( tmp, 0, sizeof(char) * len ); free( tmp ); tmp = NULL; return err; } /* */ ERROR input( char* str, unsigned int size ) { char* tmp; assert( NULL != str ); assert( 0 < size && MAX_BUFFER > size ); tmp = fgets( str, size , stdin ); assert ( tmp == str ); return SUCCEEDED; } /* */ ERROR init( char* str ) { assert( NULL != str ); memset( str, 0, sizeof(char) * MAX_BUFFER ); return SUCCEEDED; } /* */ ERROR release( char* str ) { assert( NULL != str ); memset( str, 0, sizeof(char) * MAX_BUFFER ); return SUCCEEDED; }Hello World.
shell script에서는...
shell script에서는 함수로 아래처럼...
function clarify_number { echo $1 | rev | sed 's/\([0-9]\{3\}\)/\1,/g; s/,$//' | rev }이런 코드도 괜찮지
이런 코드도 괜찮지 않나요..
void add_comma(const char *str, char *buf, int buflen)
{
while(buflen > 3)
{
*buf++ = *str++;
*buf++ = *str++;
*buf++ = *str++;
*buf++ = ',';
buflen -= 3;
}
for(; buflen > 0; buflen--)
*buf++ = *str++;
*buf++ = 0;
}
에휴.. 아무생각
에휴.. 아무생각 없이..잘못 생각했네요..
위에서 부터 3개 단위로 점이 찍히게 프로그램 됐네요.. ㅋㅋ
지워야 할건데 지울 방법을 모르겠네요...ㅠㅠ
참고하세요..
http://groups.google.co.kr/group/comp.lang.c/msg/165f11c5f832321e?
/***************************************************************************** * commify() * * * * Commify a number, that is add commas between every third digit ahead of * * the decimal point. Rounds off to abs(round) digits following the * * decimal point. Stores the results into the buf[] passed to the function * * and returns a pointer to it. Uses the standard library function fcvt() * * to do the conversion from the double val to the string of digits. * * * *****************************************************************************/ char *commify(double val, char *buf, int round) { static char *result; char *nmr; int dp, sign; result = buf; if(round < 0) /* Be sure round-off is positive */ round = -round; nmr = fcvt(val, round, &dp, &sign); /* Convert number to a string */ if(sign) /* Prefix minus sign if negative */ *buf++ = '-'; if(dp <= 0){ /* Check if number is less than 1 */ if(dp < -round) /* Set dp to max(dp, -round) */ dp = -round; *buf++ = '0'; /* Prefix with "0." */ *buf++ = '.'; while(dp++) /* Write zeros following decimal */ *buf++ = '0'; /* point */ } else{ /* Number is >= 1, commify it */ while(dp--){ *buf++ = *nmr++; if(dp % 3 == 0) *buf++ = dp ? ',' : '.'; } } strcpy(buf, nmr); /* Append rest of digits */ return result; /* following dec pt */ }--
Linux강국 KOREA
http://ydongyol.tistory.com/
--
Linux강국 KOREA
http://ydongyol.tistory.com/
사고의 확장 1. 첫
사고의 확장
1. 첫 글자가 +, -인가?
2. 뒤집어 역순으로
3. 소숫점을 찾는다
4. 세 글자마다 쉼표
5. 다시 뒤집어 정순으로
라는 망상을 해봤습니다.
자 이걸 2와 5 과정을 줄여서 효율적으로 만들면 됩니다. :)
돼지군 작업실 Revision E: E-Prot, Eightbyte OS, ...
F/OSS를 위해 뭔가 하고 싶습니다. 뭘 하면 좋을까요?
Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.
memmove 버전 /** s는
memmove 버전
/** s는 충분한 공간이 있어야 한다. */ void add_comma(char *s) { int n, l; if (!s) return; n = 3 + 1; l = strlen(s); while (l > 3) { l -= 3; memmove (s + l + 1, s + l, n); *(s + l) = ','; n += (3 + 1); } }---------
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
---------
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
오늘 따라 잠이
오늘 따라 잠이 안오는 군요. 예전 글이지만 다시 앞으로 올라와서 한번 살펴보니
common lisp 버전이 없는 듯하여 답글 하나 추가해봅니다.
common lisp은 그냥 format directives에서 지원됩니다.
장점은... 언제나 그렇듯 문제에 집중할 수 있습니다. ^^;
http://gigamonkeys.com/book/a-few-format-recipes.html
-----
오늘 나의 취미는 끝없는, 끝없는 인내다. 1973 法頂
-----
오늘 나의 취미는 끝없는, 끝없는 인내다. 1973 法頂
뭐, C나 C++ 코드들은
뭐, C나 C++ 코드들은 워낙 잘 작성들을 해놓으셔서, 그냥 지나가다가 Harbour(Clipper)라는 언어로 구현해봅니다.
function add_comma( dest ) if ( empty(dest) ) return NIL endif result := rtrim( transform("999,999,999,999,999,999,999", dest) ) return result時日也放聲大哭
時日也放聲大哭
man strfmon(3)
man strfmon(3)
PERL로 한줄코드 해봤어요 ^^
1 while ($Num =~s/(.+)(.{3})/$1,$2/);
생각해보니 틀렸네요 다시 수정합니다.
1 while ($Num =~s/(\d+)(\d{3})/$1,$2/);
댓글 달기