引数にローマ字で日本語を渡すと、一字置換した洒落を辞書から抽出するジョーキングエンジンです。
cc seenya2.c -o seenya2
としてコンパイルし、辞書ファイルを同じディレクトリに置いて実行してください。
辞書ファイルはje-edict-kanji.txtですが、探せない人のためにここに置いておきます。
n(ん)の後の母音や「やゆよ」の前には、nの後に'を付けて値渡しをしてください。
for ex. seenya shin'ya
seenya2.c
/*
* 'seenya2' joking engine 2 ver 0.70
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#define WL 256
#define RS 4
char *romaji[]={"a","i","u","e","o",
"ka","ki","ku","ke","ko",
"sa","si","su","se","so",
"ta","ti","tu","te","to",
"na","ni","nu","ne","no",
"ha","hi","hu","he","ho",
"ma","mi","mu","me","mo",
"ya","yi","yu","ye","yo",
"ra","ri","ru","re","ro",
"wa","wi","wu","we","wo",
"ga","gi","gu","ge","go",
"za","zi","zu","ze","zo",
"ja","ji","ju","je","jo",
"da","di","du","de","do",
"ba","bi","bu","be","bo",
"pa","pi","pu","pe","po",
"fa","fi","fu","fe","fo",
"ta","ti","tsu","te","to",
"dza","dzi","dzu","dze","dzo",
"kya","kyi","kyu","kye","kyo",
"sha","shi","shu","she","sho",
"cha","chi","chu","che","cho",
"nya","nyi","nyu","nye","nyo",
"hya","hyi","hyu","hye","hyo",
"mya","myi","myu","mye","myo",
"rya","ryi","ryu","rye","ryo",
"gya","gyi","gyu","gye","gyo",
"dya","dyi","dyu","dye","dyo",
"bya","byi","byu","bye","byo",
"pya","pyi","pyu","pye","pyo", };
char origword[WL][RS];
int beats;
char infile[]="je-edict-kanji.txt";
#define SOT (30*5)
bool isvowel(char c) {
switch(c) {
case 'a': case 'i': case 'u':
case 'e': case 'o': return(true);
default:
return(false);
}
}
int decomposite_word(char *o,char word[WL][RS]) {
int i,j,l;
j=0;
while(1) {
if (*o=='\0') { // 行末か?
word[j][0]='\0';
return(j);
}
if (!isvowel(*o)&&(*o==*(o+1))) { // 小さい 'っ'の処理
word[j][0]='x';
word[j][1]='\0';
o++;
j++;
continue;
}
if (*o=='n') { // "ん"の処理
if (*(o+1)=='\0') { // 次に行末
word[j][0]='n';
word[j][1]='\0';
o++;
j++;
return(j);
}
if (*(o+1)=='\'') { // 次に '
word[j][0]='n';
word[j][1]='\0';
o+=2;
j++;
continue;
}
if (!isvowel(*(o+1))&&(*(o+1)!='y')) { // 次に子音か
word[j][0]='n';
word[j][1]='\0';
o++;
j++;
continue;
}
}
for(i=0;i<SOT;i++) { // ローマ字テーブルにマッチするか?
l=strlen(romaji[i]);
if (strncmp(romaji[i],o,l)==0) {
strcpy(&(word[j][0]),romaji[i]);
o+=l;
j++;
if (*o=='-') { // 長音 − の処理 (母音を重ねる)
l=strlen((char *)(&(word[j-1][0])));
word[j][0]=word[j-1][l-1];
word[j][1]='\0';
o++;
j++;
}
break;
}
}
if (i==SOT) { // 標準以外の記法の文字の場合
while(*o!='\0') {
if (!isvowel(*o++))
continue;
word[j][0]=*(o-1);
word[j][1]='\0';
j++;
break;
}
}
}
}
int diff_word(char w[WL][RS]) {
int eq;
int i;
eq=0;
for(i=0;origword[i][0]!='\0';i++)
if (strcmp((char *)(&(origword[i][0])),(char *)(&(w[i][0])))==0)
eq+=1;
return(i-eq);
}
void printword(char word[WL][RS]) {
int i;
for(i=0;word[i][0]!='\0';i++) {
printf("%s ",(char *)&(word[i][0]));
}
printf("\n");
}
void printjoke1(char *line) {
char d1[1024];
sscanf(line,"%s",d1); //最初の単語を飛ばす
line+=strlen(d1)+1;
if (!isdigit(*line)) { // ナンバリングされてない(ひとつ)か?
sscanf(line,"%s",d1);
printf("%s\n",d1);
return;
}
// ナンバリングされている
while(1) {
if (*line=='\0')
return;
if (isdigit(*line)&&(*(line+1)=='.')&&(*(line+2)==' ')) {
line+=3;
sscanf(line,"%s",d1);
printf("%s\n",d1);
line+=strlen(d1)+1;
while(1) {
if (isdigit(*line)&&(*(line+1)=='.')&&((*line+2)==' '))
break;
if (*line=='\0')
break;
line++;
}
} else return;
}
}
void joke(char *o,FILE *fp) {
char lw[WL];
char lword[WL][RS];
char line[1024];
int f;
int b;
beats=decomposite_word(o,origword);
while(1) {
if(fgets(line,1024,fp)==NULL)
return;
sscanf(line,"%s",lw);
b=decomposite_word(lw,lword);
if (b!=beats) // 違う拍数
continue;
f=diff_word(lword);
if (f==1)
printjoke1(line);
}
}
int main(int argc,char *argv[]) {
char orig[WL];
FILE *fp;
if (argc==1)
fscanf((FILE *)stdin,"%s",orig);
else if (argc==2)
strcpy(orig,argv[1]);
else {
fprintf(stderr,"Usage: %s word\n",argv[0]);
exit(1);
}
fp=fopen(infile,"r");
if (fp==NULL) {
fprintf(stderr,"File open error.\n");
exit(1);
}
joke(orig,fp);
fclose(fp);
exit(0);
}
実行例
①
$ ./seenya2 okan
下巻
五官
悲観
伊艦
時間
下瞰
器官
区間
巨漢
お盆
お菓子
侵す
汚染
汚点
旅館
佐官
所感