文字列
Re:文字列
> 1:C言語の理解度はどの程度?
参考書を二度ほど読み終わり現在は色々試しています。
> 2:使っていい関数と駄目な関数は?
特にありませんがWinで使用します。
> 3:開発環境に制限はある?
VC++ 2010を使用しています。
> 4:入力値の範囲は?(最大値、最小値のことね)
あまり長くすると処理に時間が掛かりますよね?
単純に考えて10桁だとすると
(26+26+10)^10-1
という計算になります。
何通りあるのでしょうか・・・
とりあえず2桁から8桁くらいでやってみて
時間を計りつつ増やせそうなら自分で範囲を広げて行こうと思います。
> 5:ようは大文字&小文字で62進数っぽく(0~9、a~z、A~Zで桁上がり)表示したいってこと?
そうです。
> もしそうだとしたら、2桁の場合は
> 00~09、0a~0z、0A~0Z
> 10~19、1a~1z、1A~1Z
> 20~29、2a~2z、2A~2Z
> :
> :
> X0~X9、Xa~Xz、XA~XZ
> Y0~Y9、Ya~Yz、YA~YZ
> Z0~Z9、Za~Zz、ZA~ZZ
> じゃないの?
そうです。
それを指定桁数分やりたいのです。
参考書を二度ほど読み終わり現在は色々試しています。
> 2:使っていい関数と駄目な関数は?
特にありませんがWinで使用します。
> 3:開発環境に制限はある?
VC++ 2010を使用しています。
> 4:入力値の範囲は?(最大値、最小値のことね)
あまり長くすると処理に時間が掛かりますよね?
単純に考えて10桁だとすると
(26+26+10)^10-1
という計算になります。
何通りあるのでしょうか・・・
とりあえず2桁から8桁くらいでやってみて
時間を計りつつ増やせそうなら自分で範囲を広げて行こうと思います。
> 5:ようは大文字&小文字で62進数っぽく(0~9、a~z、A~Zで桁上がり)表示したいってこと?
そうです。
> もしそうだとしたら、2桁の場合は
> 00~09、0a~0z、0A~0Z
> 10~19、1a~1z、1A~1Z
> 20~29、2a~2z、2A~2Z
> :
> :
> X0~X9、Xa~Xz、XA~XZ
> Y0~Y9、Ya~Yz、YA~YZ
> Z0~Z9、Za~Zz、ZA~ZZ
> じゃないの?
そうです。
それを指定桁数分やりたいのです。
Re:文字列
まず0から9、aからz、AからZを順番にchar型配列に格納します。(cとします。)
表示する桁数のint型配列を用意します。(aとします。)
aを0で初期化します。
表示する文字列用のバッファを用意します。(sとします。)
表示する文字列の作成
s[0]=0;
for(i=0;i<桁数;i++;){
sprintf(s,"%s%c",s,c[a]);
}
sを表示します。
aの最後を1増やします。
その結果62以上になったら0にしてひとつ前を1増やします。
62以上になったら同じようにします。
最初が62を越えたら終了します。
表示する文字列を作成して表示します。
繰り返します。
間違っていたらごめんなさい。
表示する桁数のint型配列を用意します。(aとします。)
aを0で初期化します。
表示する文字列用のバッファを用意します。(sとします。)
表示する文字列の作成
s[0]=0;
for(i=0;i<桁数;i++;){
sprintf(s,"%s%c",s,c[a]);
}
sを表示します。
aの最後を1増やします。
その結果62以上になったら0にしてひとつ前を1増やします。
62以上になったら同じようにします。
最初が62を越えたら終了します。
表示する文字列を作成して表示します。
繰り返します。
間違っていたらごめんなさい。
Re:文字列
結構、まわりくどいやり方になっちまった(^_^;)
表示が違うけど、それは自分で修正してくださいなm(__)m
表示が違うけど、それは自分で修正してくださいなm(__)m
#include <math.h> #include <stdio.h> #include <string.h> #define STR_MAX_LEN 10 + 1 const char parts[/url] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; void reverse(int n, char* str) { if (n >= 0) { putc(*(str + n), stdout); reverse(n - 1, str); } } void convert(int digit) { char str[STR_MAX_LEN] = {0, }; int i = 0; unsigned long long cnt = 0; unsigned long long tmp = 0; unsigned long long max = 0; max = (unsigned long long)(pow((long double)(62), digit) - 1); for (cnt = 0 ; cnt <= max; ++cnt) { tmp = cnt; for (i = 0; i < digit; ++i) { str = parts[tmp % 62]; tmp /= 62; if (tmp == 0) break; } printf("%I64u = ", cnt); reverse((int)strlen(str), str); putc('\n', stdout); } } int main(void) { convert(5); return 0; }
Re:文字列
こちらの方が色々と扱いやすいかな?
#include <math.h> #include <stdio.h> #include <string.h> #define STR_MAX_LEN 10 + 1 const char parts[/url] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; void reverse(int n, int m, const char* src, char* dest) { if (n >= 0) { *(dest + m) = *(src + n); reverse(n - 1, m + 1, src, dest); } } /* val = 変換したい値 base = 基数(10進数なら10、16進数なら16、62進数なら62) dig = 最大文字数 str = 変換後の文字列が格納される領域へのポインタ */ void convert(const unsigned long val, const int base, const int dig, char* str) { char buf[STR_MAX_LEN] = {0, }; int i = 0; unsigned long tmp = 0; tmp = val; for (i = 0; i < dig; ++i) { buf = parts[tmp % base]; tmp /= base; if (tmp == 0) break; } /* 文字列の反転 */ reverse((int)strlen(buf) - 1, 0, buf, str); } int main(void) { char* str[STR_MAX_LEN] = {0, }; unsigned long i = 0; for (i = 0; i < 4000; ++i) { convert(i, 62, 10, str); printf("%s ", str); } return 0; }
Re:文字列
私も便乗させていただきたくw こんなのいかがでしょうか。
#include <stdio.h>
#include <string>
// i^pを返す
int ipow(int i,int p) {
int r=1;
while(p--) r*=i;
return r;
}
void main(void)
{
int digit=2;
const char *chartbl="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i,n=(int)strlen(chartbl),imax=ipow(n,digit);
const int BUFMAX=8;
char buf[BUFMAX]={0},*p;
for(i=0;i<imax;i++) {
p=buf+BUFMAX-2;
for(int j=i;j;j/=n) *p--=chartbl[j%n];
p++;
printf("%d : %s\n",i,p);
}
}
#include <stdio.h>
#include <string>
// i^pを返す
int ipow(int i,int p) {
int r=1;
while(p--) r*=i;
return r;
}
void main(void)
{
int digit=2;
const char *chartbl="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i,n=(int)strlen(chartbl),imax=ipow(n,digit);
const int BUFMAX=8;
char buf[BUFMAX]={0},*p;
for(i=0;i<imax;i++) {
p=buf+BUFMAX-2;
for(int j=i;j;j/=n) *p--=chartbl[j%n];
p++;
printf("%d : %s\n",i,p);
}
}
Re:文字列
考えてみました。
少し書き直しました。
#include <stdio.h> #include <stdlib.h> #include <string.h> int func(int m) { const char *s = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const int n = (int)strlen(s); int *p; if(m <= 0) return 0; if(!(p = calloc(m, sizeof(int)))) return 0; while(1){ int i; for(i = 0; i < m; ++ i) putchar(s[p]); putchar(' '); while(-- i >= 0 && ++ p == n) p = 0; if(i < 0) break; } free(p); return 1; } int main(void) { func(3); return 0; }

Re:文字列
バグさん
> 今度は逆の処理ですね。
>
> つまり、62進数から10進数への変換処理をしてやる必要がありますね。
>
> 1桁目の数値は1~Z(1~61)
> 2桁目の数値は(1~Z)×62
> 3桁目の数値は(1~Z)×62×62
> 4桁目の数値は(1~Z)×62×62×62
>
> ってな具合で任意の桁まで繰り返していき、全ての桁の数値の総和を求めれば10進数への変換は終了です。
> この処理で始まりの値と終わりの値を求めてやり、forループとかで繰り返せばよいだけですね。
>
>
> さて、ここまでは理解できますか?
>
色々やってみてるのですが
いまいちわかりません>_<
ちなみに
> 1桁目の数値は1~Z(1~61)
> 2桁目の数値は(1~Z)×62
> 3桁目の数値は(1~Z)×62×62
> 4桁目の数値は(1~Z)×62×62×62
これなんですけど
1~Z(1~61)
でいいのですか?
0~Z(0~61)
にならないのはなぜですか?
たとえば
「2Cz」という文字列は
1桁目・・・z(36)
2桁目・・・C(39*62=2418)
3桁目・・・2(3*62*62=11532)
なので
36+2418+11532=13986
ということでしょうか?
※0~Z(0~61)で計算してます。
同じように終わりの文字列を計算して
14986だったとしたら
while(13986 <= 14986) //変数ではなく例でわかりやすいように数字にしてます
という具合でループして
10進数をまた62進数にするといことですか?
> 今度は逆の処理ですね。
>
> つまり、62進数から10進数への変換処理をしてやる必要がありますね。
>
> 1桁目の数値は1~Z(1~61)
> 2桁目の数値は(1~Z)×62
> 3桁目の数値は(1~Z)×62×62
> 4桁目の数値は(1~Z)×62×62×62
>
> ってな具合で任意の桁まで繰り返していき、全ての桁の数値の総和を求めれば10進数への変換は終了です。
> この処理で始まりの値と終わりの値を求めてやり、forループとかで繰り返せばよいだけですね。
>
>
> さて、ここまでは理解できますか?
>
色々やってみてるのですが
いまいちわかりません>_<
ちなみに
> 1桁目の数値は1~Z(1~61)
> 2桁目の数値は(1~Z)×62
> 3桁目の数値は(1~Z)×62×62
> 4桁目の数値は(1~Z)×62×62×62
これなんですけど
1~Z(1~61)
でいいのですか?
0~Z(0~61)
にならないのはなぜですか?
たとえば
「2Cz」という文字列は
1桁目・・・z(36)
2桁目・・・C(39*62=2418)
3桁目・・・2(3*62*62=11532)
なので
36+2418+11532=13986
ということでしょうか?
※0~Z(0~61)で計算してます。
同じように終わりの文字列を計算して
14986だったとしたら
while(13986 <= 14986) //変数ではなく例でわかりやすいように数字にしてます
という具合でループして
10進数をまた62進数にするといことですか?
Re:文字列
>>しんごさん
おっと、失礼しました。
たしかに1~Z(1~61)ではなく、0~Z(0~61)の間違いですね。
とりあえず書いてみましたので、解析してみてください。
あまり深くデバッグしていないのでバグが潜んでいるかもしれませんが、ご容赦を。
※unsigned long longを多用しているのは、他の型で62進数を扱うとあっという間にオーバーフローしてしまうからです(^_^;)
※使い道
仕事で数字とアルファベットを使用した36進数ってのは使った事がありますね。
データの簡単な暗号化に使うくらいしか思いつかないですね。
おっと、失礼しました。
たしかに1~Z(1~61)ではなく、0~Z(0~61)の間違いですね。
とりあえず書いてみましたので、解析してみてください。
あまり深くデバッグしていないのでバグが潜んでいるかもしれませんが、ご容赦を。
※unsigned long longを多用しているのは、他の型で62進数を扱うとあっという間にオーバーフローしてしまうからです(^_^;)
※使い道
仕事で数字とアルファベットを使用した36進数ってのは使った事がありますね。
データの簡単な暗号化に使うくらいしか思いつかないですね。
#include <stdio.h> #include <stdlib.h> #include <string.h> /* unsigned long long型のべき乗計算 */ unsigned long long pow_ull(unsigned long long val, unsigned int cnt) { unsigned long long ret = 1; for (; cnt > 0; --cnt) ret *= val; return ret; } /* 10進数からN進数へ変換 */ void cvt10ToN(unsigned long long val, const unsigned int base, unsigned int dig, char* str) { const char* parts = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; sprintf(str, "%0*d", dig, 0); for (; dig > 0; --dig, val /= base) if (val != 0) str[dig - 1] = parts[val % base]; } /* 1文字を10進数値へ変換 */ unsigned long long cvtCharTo10(const char ch) { const char* parts = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; unsigned long long i = 0; unsigned long long len = (unsigned long long)strlen(parts); for (i = 0; i < len; ++i) if (ch == *(parts + i)) return i; return 0; } /* N進数文字列を10進数値へ変換 */ unsigned long long cvtStrTo10(const char* str, const unsigned int base) { unsigned int i = 0; unsigned int dig = (unsigned int)strlen(str); unsigned long long ret = 0; for (i = 0; i < dig; ++i) ret += cvtCharTo10(*(str + i)) * pow_ull(base, dig - i - 1); return ret; } void main(void) { char str[256]; unsigned long long i = 0; for (i = 0; i < 100000; ++i) { cvt10ToN(i, 62, 10, str); printf("%s = %I64u\n", str, cvtStrTo10(str, 62)); } }
Re:文字列
# 使い道
私は、似たようなロジックを、日時を表す時に使っています。
例えば、2010 8/27 11:31:23 を表すのに、
単に 年月日 時分秒 を結合すると、20100827113123 となりますが、
一見して「日時だなっ」という印象を避けたい場合に、
年(の下2桁),月,日, 時,分,秒 をそれぞれ 0-9a-zA-Z に変換してから結合すると
a8rbvn
となります。
「だからどうした」って感じかもですけど^^;
以下、ソースを載せます。
phpですけど...概念は伝わるかと。
$x60tas="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
function x60ta($s) {
global $x60tas;
return substr($x60tas,intval($s),1);
}
$nocache=date("YmdHis",time());
$nocache=x60ta(substr($nocache, 2,2)).
x60ta(substr($nocache, 4,2)).
x60ta(substr($nocache, 6,2)).
x60ta(substr($nocache, 8,2)).
x60ta(substr($nocache,10,2)).
x60ta(substr($nocache,12,2));
私は、似たようなロジックを、日時を表す時に使っています。
例えば、2010 8/27 11:31:23 を表すのに、
単に 年月日 時分秒 を結合すると、20100827113123 となりますが、
一見して「日時だなっ」という印象を避けたい場合に、
年(の下2桁),月,日, 時,分,秒 をそれぞれ 0-9a-zA-Z に変換してから結合すると
a8rbvn
となります。
「だからどうした」って感じかもですけど^^;
以下、ソースを載せます。
phpですけど...概念は伝わるかと。
$x60tas="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
function x60ta($s) {
global $x60tas;
return substr($x60tas,intval($s),1);
}
$nocache=date("YmdHis",time());
$nocache=x60ta(substr($nocache, 2,2)).
x60ta(substr($nocache, 4,2)).
x60ta(substr($nocache, 6,2)).
x60ta(substr($nocache, 8,2)).
x60ta(substr($nocache,10,2)).
x60ta(substr($nocache,12,2));