//音声認識ルールを登録する部分の詳細な実行です。正規表現のネストがあるので再起してます。 xreturn::r<bool> JuliusPlus::AddRegexpImpl(const CallbackDataStruct & callback,const std::string & str, JuliusPlusRule* stateHandle) { // _USE_WINDOWS_ENCODING; std::string matchString; //正規表現をパースしながら回す. const char * p = str.c_str(); const char * splitPos = p; JuliusPlusRule* currentRule = stateHandle; for( ; *p ; ++p ) { #ifdef _WINDOWS_ if ( issjiskanji(*p) ) { p ++; continue; } #endif if (*p == '(') { //閉じ括弧まで飛ばす. ) int nest = 1; const char* n = p + 1; for( ; *n ; ++n ) { #ifdef _WINDOWS_ if ( issjiskanji(*n) ) { n ++; continue; } #endif if (*n == '(') { ++nest ; } else if (*n == ')') { --nest ; if (nest <= 0) { break; } } } //ネストする前の部分 matchString = std::string(splitPos, 0 ,p - splitPos); //ネストしている部分を格納するルールを作る. JuliusPlusRule* nestRule; //お目当ての()ネストを格納する部分を作る //キャプチャー? if (*(p+1) == '?' && *(p+2) == ':') { nestRule = new JuliusPlusRule(callback); } else { nestRule = new JuliusPlusRule( this->LocalCaptureRuleNodeCount++ , callback); } if (matchString.empty()) {//先行文字列が空 currentRule->AddNestRule(nestRule); } else {//文字列だけを入れると OR扱いになってしまうので、ネストを格納するネストを作らないとダメ。 JuliusPlusRule* firstNestRule = new JuliusPlusRule(callback); firstNestRule->AddWord(matchString); firstNestRule->AddNestRule(nestRule); currentRule->AddNestRule(firstNestRule); } //かっこの後にも構文が連続する場合、そのツリーを作成する. if (*n == '\0' || *(n+1) == '\0' || *(n+1) == '|') {//閉じかっこで構文がとまる場合はそこで終端 //nop } else {//さらに構文が続いている場合 JuliusPlusRule * afterRule = new JuliusPlusRule(callback); nestRule->SetCombineRule(afterRule); currentRule = afterRule; } //ネストしているルールを再帰して実行. matchString = std::string(p+1 , 0 , (int) (n - p - 1) ); auto r = this->AddRegexpImpl(callback,matchString, nestRule); if(!r) { return xreturn::errnoError(r); } p = n ; splitPos = n + 1; //+1は最後の ) を飛ばす. iは forの ++i で i == splitPos となる。(わかりにくい) } else if (*p == '|') { matchString = std::string(splitPos,0 , (int) (p - splitPos)); if (matchString.length() >= 1) { currentRule->AddWord(matchString); } //空分岐 (A|) のような場合、空ノードを入れる. if (matchString.length() <= 0 || *(p+1) == '\0' ) { assert(0); //not implement! 未実装! currentRule->AddWord(""); } splitPos = p + 1; currentRule = stateHandle; } else if (*p == '.' && *(p+1) == '+') { assert(0); //not implement! 未実装! // currentRule->AddWord("*"); p += 1; splitPos = p + 1; } } //最後の残り matchString = std::string(splitPos , 0 , (int) (p - splitPos) ); if ( matchString.length() >= 1 &&str.length() >= 1 && *(p-1) != ')') { currentRule->AddWord(matchString ); } return true; }
int GetToken(char *buf,int len,TOKEN *token, char *token_separate,char *token_separate_point) { int token_start,token_len; int i,j; char point[10]; token->token=NULL; token->size=0; token->no=0; token_start=0; for(i=0;i<len;i++){ /* SJIS漢字1バイト目、エスケープ */ if(issjiskanji(buf[i])||buf[i]=='\\'){ i++; } else if(buf[i]=='"'){ /* "文字列 */ for(j=i+1;j<len;j++){ /* SJIS漢字1バイト目、エスケープ */ if(issjiskanji(buf[j])||buf[j]=='\\'){ j++; continue; } if(buf[j]=='"'){ break; } } i=j; } else if(buf[i]=='\''){ /* '文字列 */ for(j=i+1;j<len;j++){ /* SJIS漢字1バイト目、エスケープ */ if(issjiskanji(buf[j])||buf[j]=='\\'){ j++; continue; } if(buf[j]=='\''){ break; } } i=j; } else if(strchr(token_separate,buf[i])!=NULL){ /* 分離文字 */ token_len=i-token_start; if(token_len>0){ AddToken(token,&buf[token_start],token_len); } token_start=i+1; } else if(strchr(token_separate_point,buf[i])!=NULL){ /* 区切り分離文字 */ token_len=i-token_start; if(token_len>0){ AddToken(token,&buf[token_start],token_len); } sprintf(point,"%c",buf[i]); AddToken(token,point,1); token_start=i+1; } } token_len=i-token_start; if(token_len>0){ AddToken(token,&buf[token_start],token_len); } return(0); }
//音声認識ルールを構築します。 正規表現にも対応しています。 xreturn::r<bool> JuliusPlus::AddRegexp(const CallbackDataStruct & callback,const std::string & str ,JuliusPlusRule* stateHandle ) { //unixへの移植を考えて wchar_tはやめることにした。 //unix で UTF8 を使っている限りはマルチバイトに悩むことはないでしょう。 EUCとかレガシーなシステムは知らん。 // _USE_WINDOWS_ENCODING; //一番最初だけ正規表現の構文変換をかける. //難しすぎる表現を簡単なゆとり仕様に直して、パースしやすくする。 // .+ --> (:?.*) // (まる|さんかく)? --> (まる|さんかく|) 正しい正規表現としてはエラーだが、このエンジンの場合容認する. // なのは? --> なの(は|) std::string optstr; optstr.reserve(str.size()); for( const char * p = str.c_str() ; *p ; ++p ) { #ifdef _WINDOWS_ if ( issjiskanji(*p) ) { optstr += *p; optstr += *(p+1); p ++; continue; } #endif if ( *p == '.' && *(p+1) == '+') { // .+ --> (:?.*) optstr += "(?:.+)"; ++p; } else if (*p == '(' && *(p+1) == '?' && *(p+2) == ':' ) { optstr += "(?:"; p+=2; } else if (*(p+1) == '?') { if (*p == ')') {// (まる|さんかく)? --> (まる|さんかく|) optstr += "|)"; } else {// なのは? --> なの(は|) optstr += std::string("(?:") + *p + "|)"; } ++p; } else if (*p == '*' || *p == '+' || *p == '.' || *p == '[' || *p == ']') { // throw exception(std::string("") + "現在は、メタ文字 " + p + " は利用できません。利用可能なメタ文字 () | .+ ?"); return xreturn::error(std::string("") + "現在は、メタ文字 " + p + " は利用できません。利用可能なメタ文字 () | .+ ?"); } else { optstr += *p; } } //正規表現 captureの番号。 this->LocalCaptureRuleNodeCount = 1; //このルールを収めるメールを作る。(この処理は厳格に見ると非効率だが、とりあえずこれで) JuliusPlusRule* firstNestRule = new JuliusPlusRule(callback); stateHandle->AddNestRule(firstNestRule); //正規表現パースを本気でやる return AddRegexpImpl(callback,optstr, firstNestRule); }