文字列の置換
N88BASICの文字列関数で遊ぶ
配列(ポインタ)からデータを探す
コマンドライン引数の表示
文字列を分解する
文字列を置換します。bufは置換後の大きさが必要です。
#include <stdio.h> #include <string.h> /* 置換する。 buf の中の mae を ato にする。成功=1 失敗=0 */ int strrep(char *buf, char *mae, char *ato) { char *mituke; size_t maelen, atolen; maelen = strlen(mae); atolen = strlen(ato); if (maelen == 0 || (mituke = strstr(buf, mae)) == NULL) return 0; memmove(mituke + atolen, mituke + maelen, strlen(buf) - (mituke + maelen - buf ) + 1); memcpy(mituke, ato, atolen); return 1; } main() { char buf[100]; strcpy(buf, "肉肉肉肉肉肉肉肉肉肉"); while (strrep(buf, "肉", "土下座")) ; printf("%s\n", buf); }
N88BASICのLEFT$,MID$,RIGHT$関数を作ってみました。 MID$は文字の先頭が1になるようにしました。 あと、TIME$とDATE$を作ってみました。でも関数です。 とても便利でしょう。
Boehm GC 6.8を使ってみました。もしかしたら使い方間違っているかも。 普通のmallocとかだったら、どこかでfreeしないといけませんね。
#include <stdio.h> #include <string.h> #include <time.h> #include "gc.h" /* buf の左から n 文字までを返す。*/ char *LEFT$(char *buf, int n) { char *tmp; size_t buflen = strlen(buf); if (buflen < n || n < 0 ) return NULL; tmp = (char *)GC_MALLOC(n + 1); memcpy(tmp, buf, n); tmp[n] = 0; return tmp; } /* buf の n 文字目から l 文字を返す。 */ char *MID$(char *buf, int n, int l) { char *tmp; size_t buflen = strlen(buf); n--; if (buflen < n || buflen < n + l || n < 0) return NULL; tmp = (char *)GC_MALLOC(l + 1); memcpy(tmp, buf + n, l); tmp[l] = 0; return tmp; } /* buf の右から n 文字を返す。 */ char *RIGHT$(char *buf, int n) { char *tmp; size_t buflen = strlen(buf); if (buflen < n || n < 0 ) return NULL; tmp = (char *)GC_MALLOC(n + 1); memcpy(tmp, buf + buflen - n, n); tmp[n] = 0; return tmp; } /* 時間をhh:mm:ssで返す */ char *TIME$(void) { time_t tim; struct tm *t_st; char *tmp = GC_MALLOC(9); time(&tim); t_st = localtime(&tim); sprintf(tmp, "%02d:%02d:%02d", t_st->tm_hour, t_st->tm_min, t_st->tm_sec); return tmp; } /* 日付をyy/mm/ddで返す */ char *DATE$(void) { time_t tim; struct tm *t_st; char *tmp = GC_MALLOC(9); time(&tim); t_st = localtime(&tim); while(t_st->tm_year > 99) t_st->tm_year -= 100; sprintf(tmp, "%02d/%02d/%02d", t_st->tm_year, t_st->tm_mon + 1, t_st->tm_mday); return tmp; } main() { char *t = (char *)GC_MALLOC(100); strcpy(t, "あqwせdrftgyふじこp;"); printf("%s\n", LEFT$(t, 4)); printf("%s\n", MID$(t, 21, 6)); printf("%s\n", RIGHT$(t, 8)); printf("日時%s 時間%s\n", DATE$(), TIME$()); printf("%s\n", RIGHT$(TIME$(), 2)); }
N88BASICのSEARCH関数のようなものです。 char,short,longの3つの型に対応しています。
使い方はSEARCH(配列名, 配列の大きさ, 型, 探す値)です。
#include <stdio.h> #include <string.h> #include <stdlib.h> /* 配列からデータを見つける。 * 戻り値:見つかった位置(先頭=1)、0なら無し。 * hairetu:配列 * saizu:配列のサイズ * kata:型 * mituke:探すデータ */ int SEARCH(void *hairetu,int saizu,int kata,int mituke) { int n; switch (kata) { case sizeof(char): for (n = 0; n < saizu; n++) if (*((char *)hairetu + n) == mituke) return n+1; break; case sizeof(short): for (n = 0; n < saizu; n++) if (*((short *)hairetu + n) == mituke) return n+1; break; case sizeof(long): for (n = 0; n < saizu; n++) if (*((long *)hairetu + n) == mituke) return n+1; break; } /* 見つからない、型が違う*/ return 0; } main(){ /* お試し */ char *ca; long la[] ={1,2,3,4,5,6,7,8,9,10}; printf("%d\n", SEARCH(la, sizeof la, sizeof *la, 7));/* 配列 */ ca = malloc(100); strcpy(ca,"debudebu@nikuniku.29.jp"); printf("%d\n", SEARCH(ca, strlen(ca), sizeof *ca, '@'));/* ポインタ */ free(ca); }
main関数は当然関数です。だから再帰呼び出しが可能です。 コマンドライン引数を順に表示するプログラムです。 N88-BASICでゲームを作るとき、ゲームオーバーなどで初期化させたいときにrunさせるというテクニックがあります。 C言語で同じようなことをやろうと思ってmain関数を呼んでもスタックに積まれるため、初期化にはならないので注意してください。
#include <stdio.h> main(int argc, char *argv[]) { if (argc) { main(--argc, argv); printf("%d %s\n", argc, argv[argc]); } }
perlなどのsplit関数って便利ですよね。 あれに似たような関数を作ってみました。名前はそのままsplit関数です。
使い方は split(文字列, デリミタ, 受け取るポインタ..., NULL)です。 可変引数を使っているため、受け取るポインタの数は無制限です。 最後のNULLは番人なので、これが無かったら多分落ちます。
標準関数のstrtokでも良いのですが、引数の文字列を勝手に書き換えられるので、 あえて自分でmystrtokを定義しています。 freeのタイミングを考えるのが嫌なので、gcを使っています。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include "gc.h" #pragma comment (lib, "gc.lib") #define malloc GC_MALLOC_ATOMIC /* strtokの文字列版。 */ char *mystrtok(char *s, char *t) { static char *buf = NULL; /* 実際のデータ */ static char *atamap; /* 頭ポインタ */ char *oshirip; /* お尻ポインタ */ char *p; if (s != NULL) { buf = malloc(strlen(s)+1); strcpy(buf, s); atamap = buf; /* atamapは先頭を指す */ } oshirip = strstr(atamap, t); /* oshiripは区切り文字を指す */ if (oshirip == NULL) return NULL; *oshirip = 0; p = atamap; atamap = oshirip + strlen(t); /* 次の頭 */ return p; } /* strの文字列をdelimiterで区切る。 */ int split(char *str, char *delimiter, ...) { int count = 0; char *p; char *buf; va_list ap; va_start(ap, delimiter); p = mystrtok(str, delimiter); buf = va_arg(ap, char *); if (p == NULL || buf == NULL) return count; strcpy(buf, p); while ((buf = va_arg(ap, char *)) != NULL && (p = mystrtok(NULL, delimiter)) != NULL) { strcpy(buf, p); count++; } va_end(ap); return count; } typedef struct { char name[100]; char mail[100]; char date[100]; char text[1000]; } RES; main() { char *data = "名無し<>debudebu@nikuniku.29.jp<>1549年12月13日<>これはテストです。あいうえー<>"; RES res; split(data, "<>", res.name, res.mail, res.date, res.text, NULL); printf("name : %s mail : %s date : %s\n%s\n", res.name, res.mail, res.date, res.text); }