原来觉得很简单,是个控制台程序,后来发现实际上不这么简单。慢慢分析吧,
先加个类,CPARSERV1,
#pragma once
#define PARSER_BUFFER_SIZE 256
#define PARSER_DEFAULT_COMMENT "#"
#define PARSER_MAX_COMMENT 16
class CPARSERV1
{
public:
CPARSERV1(void);
~CPARSERV1(void);
public:
//打开文件
int Open( char * filename );
//重置文件系统
int Reset();
public:
FILE * fstream; //文件指针
char buffer[PARSER_BUFFER_SIZE]; //缓冲区
int length; //当前行长度
int num_lines; //处理了多少行
char comment[PARSER_MAX_COMMENT];
};
逐步进行,首先是构造函数和析构函数
CPARSERV1::CPARSERV1(void)
{
fstream = NULL;
Reset();
}
CPARSERV1::~CPARSERV1(void)
{
Reset();
}
看看RESET()中有什么内容,
打开文件,
int CPARSERV1::Open( char * filename )
{
Reset();
if ( ( fstream = fopen( filename, "r")) != NULL )
{
return 1;
}
else
{
return 0;
}
}
下面进行读取一行文本
有几个模式,首先定义下:
#define PARSER_STRIP_EMPTY_LINES 1 //删除空行
#define PARSER_LEAVE_EMPTY 2 //保留空行
#define PARSER_STRIP_WS_ENDS 4 //删除行尾的空格
#define PARSER_LEAVE_WS_ENDS 8 //保留行尾的空格
#define PARSER_STRIP_COMMENTS 16 //删除注释
#define PARSER_LEAVE_COMMENTS 32 //保留注释
//重置系统
int CPARSERV1::Reset()
{
if (fstream)
{
fclose(fstream);
}
fstream = NULL;
memset( buffer, 0, sizeof(buffer));
length = 0;
num_lines = 0;
strcpy(comment, PARSER_DEFAULT_COMMENT);
return 1;
}
//关闭文件
int CPARSERV1::Close()
{
return ( Reset());
}
//读取下一行,如果有,则返回该行;如果没有,返回NULL
char * CPARSERV1::GetLine( int mode )
{
char * string;
if (fstream)
{
if ( mode & PARSER_STRIP_EMPTY_LINES )
{
while( 1)
{
if ( ( string = fgets( buffer, PARSER_BUFFER_SIZE, fstream)) == NULL )
{
break;
}
int slength = strlen( string );
int sindex = 0;
while( isspace( string[sindex]))
{
sindex ++;
}
if ( ( slength - sindex ) > 0 )
{
memmove( ( void * ) buffer, ( void * ) & string[sindex], ( slength - sindex) + 1 );
string = buffer;
slength = strlen( string );
if ( mode & PARSER_STRIP_COMMENTS )
{
char * comment_string = strstr( string, comment );
if ( comment_string == NULL )
{
break;
}
int cindex = ( int ) ( comment_string - string );
if ( cindex == 0 )
{
continue;;
}
else
{
comment_string[0] = 0;
break;
}
}
break;
}
}
}
else
{
string = fgets( buffer, PARSER_BUFFER_SIZE, fstream );
}
if ( string )
{
num_lines ++;
if ( mode & PARSER_STRIP_WS_ENDS )
{
StringLtrim( buffer );
StringRtrim( buffer );
}
length = strlen( buffer );
return string;
}
else
{
return NULL;
}
}
else
{
return NULL;
}
}
//去掉左空格
char * CPARSERV1::StringLtrim( char * string )
{
int sindex = 0;
int slength = strlen( string );
if ( !string || slength == 0 )
{
return string;
}
while( isspace(string[sindex]) && sindex < slength )
{
string[sindex ++ ] = 0;
}
memmove( ( void * )string, ( void * ) & string[sindex], ( slength - sindex ) + 1 );
return string;
}
//去掉右空格
char * CPARSERV1::StringRtrim( char * string )
{
int sindex = 0;
int slength = strlen( string );
if ( !string || slength == 0 )
{
return string;
}
sindex = slength - 1;
while( isspace(string[sindex]) && sindex >= 0 )
{
string[sindex-- ] = 0;
}
return string;
}
先弄个简单的,设置注释字符串,比如“#”、“;”和“//”,很简单, 就是长度不足,则用字符串代替
int CPARSERV1::SetComment(char *string)
{
if( strlen( string ) < PARSER_MAX_COMMENT )
{
strcpy( comment, string );
return ( 1 );
}
else
return ( 0 );
}
应该模式匹配是最重要的了,不过,先进行下外围吧,辅助函数
字符剔除函数
int CPARSERV1::StripChars(char *string_in, char *string_out, char *strip_chars, int case_on )
{
int num_extracts = 0, //删除的字符个数
index_in = 0, //输入的当前索引
index_out = 0, //输出的当前索引
sindex, //循环变量
slength = strlen( strip_chars ); //删除的字符串长度
//错误检测
if( !string_in || !string_out || strlen( string_in ) == 0 )
return ( 0 );
//如果没有可替换的
if( !strip_chars || strlen( strip_chars ) == 0 )
{
strcpy( string_out, string_in );
return ( 0 );
}
//决定情况是否重要
if( case_on == 1 )
{
//逐字符串拷贝
while( string_in[index_in] )
{
for( sindex = 0; sindex < slength; sindex++ )
{
if( string_in[index_in] == strip_chars[sindex] )
{
//跳过该输入字符(它被删除了)
index_in ++;
num_extracts ++;
break;
}
}
//删除字符串是否找到?
if( sindex >= slength )
{
string_out[index_out++] = string_in[index_in++];
}
}
}
else
{
//不敏感的情况下逐字符串拷贝
while( string_in[index_in] )
{
for( sindex = 0; sindex < slength; sindex++ )
{
if( toupper( string_in[index_in] ) == toupper( strip_chars[sindex] ) )
{
//跳过该输入字符(它被删除了)
index_in ++;
num_extracts ++;
break;
}
}
//删除字符串是否找到?
if( sindex >= slength )
{
string_out[index_out++] = string_in[index_in++];
}
}
}
//消除输出字符串
string_out[index_out] = 0;
return num_extracts;
}
下面进行替换字符串中的字符函数,主要是在StripChars的基础上,再加上指定字符,将其隔开,因此多了个char参数
int CPARSERV3::ReplaceChars(char *string_in, char *string_out, char *replace_chars, char rep_char, int case_on )
{
int num_replacements = 0, //删除的字符个数
index_in = 0, //输入的当前索引
index_out = 0, //输出的当前索引
sindex, //循环变量
slength = strlen( replace_chars ); //删除的字符串长度
//错误检测
if( !string_in || !string_out || strlen( string_in ) == 0 )
return ( 0 );
//如果没有可替换的
if( !replace_chars || strlen( replace_chars ) == 0 )
{
strcpy( string_out, string_in );
return ( 0 );
}
//决定情况是否重要
if( case_on == 1 )
{
//逐字符串拷贝
while( string_in[index_in] )
{
for( sindex = 0; sindex < slength; sindex++ )
{
if( string_in[index_in] == replace_chars[sindex] )
{
//替换之
string_out[index_out++] = rep_char;
index_in ++;
num_replacements ++;
break;
}
}
//删除字符串是否找到?
if( sindex >= slength )
{
string_out[index_out++] = string_in[index_in++];
}
}
}
else
{
//不敏感的情况下逐字符串拷贝
while( string_in[index_in] )
{
for( sindex = 0; sindex < slength; sindex++ )
{
if( toupper( string_in[index_in] ) == toupper( replace_chars[sindex] ) )
{
//替换之
string_out[index_out++] = rep_char;
index_in ++;
num_replacements ++;
break;
}
}
//删除字符串是否找到?
if( sindex >= slength )
{
string_out[index_out++] = string_in[index_in++];
}
}
}
//消除输出字符串
string_out[index_out] = 0;
return num_replacements;
}
下面判断字符串是否可以转为浮点数,如果可以,则返回转换后的值,前提是对于
[空格][符号][.][{d|D|e|E}[符号]数字]模式的
float CPARSERV1::IsFloat(char *fstring)
{
char * string = fstring;
//空格
while( isspace( * string ) )
string ++;
//符号
if( * string == '+' || *string == '-' )
string++;
//符号
while( isdigit( *string ) )
string++;
//[.]
if( *string == '.' )
{
string++;
while( isdigit( * string ) )
string++;
}
//[{d|D|e|E}[符号]数字]
if( * string == 'e' || *string == 'E' || * string == 'd' || * string == 'D' )
{
string ++;
//符号
if( * string == '+' || * string == '_' )
string ++;
//[数字]
while( isdigit( * string ) )
string++;
}
//经过上述处理后,如果到达了字符串末尾,则可以转换为浮点数,否则,不是浮点数
if( strlen( fstring ) == ( int ) ( string - fstring ) )
return atof( fstring );
else
return FLT_MIN;
}
下面进行将字符串转换为整数
int CPARSERV1::isInt(char *fstring)
{
char * string = fstring;
//空格
while( isspace( * string ) )
string ++;
//符号
if( * string == '+' || *string == '_' )
string++;
//[数字]
while( isdigit( * string ) )
string++;
//经过上述处理后,如果到达了字符串末尾,则可以转换为浮点数,否则,不是浮点数
if( strlen( fstring ) == ( int ) ( string - fstring ) )
return atoi( fstring );
else
return INT_MIN;
}
下面进行本DMEO最难的地方,模式匹配了。即在传入的字符串中查找与传入的模式匹配的字串,
首先定义存储空间,用来存储字符串、浮点数或者整数
//模式匹配参数存储空间
//函数patter()返回时,匹配的内容将存储在这些数组中,
//匹配任何字符串
char pstrings[PATTERN_MAX_ARGS][PATTERN_BUFFER_SIZE];
int num_pstrings;
//匹配任何浮点数
float pfloats[PATTERN_MAX_ARGS];
int num_pfloats;
//匹配任何整数
int pints[PATTERN_MAX_ARGS];
int num_pints;
模式匹配语言有以下几种
[i] 与整数匹配
[f] 与浮点数匹配
[s=d] 与包含d个字符的任何字符串匹配
[s<d] 与长度小于d个字符的任何字符串匹配
[s>d] 与长度大于d个字符的任何字符串匹配
[‘sss…s’] 与单引号中的字符串匹配
如要匹配“vertex: 34.56 23.67 10.90”可使用“[‘vertex’][f][f][f]”,此时num_floats=3,pfloats[]={34.56,23.67,10.90}.
模式匹配语言实现就是如下所示
int CPARSERV1::Pattern_Match(char *string, char *pattern, ...)
{
char token_type[PATTERN_MAX_ARGS]; //类型,f,i,s,l
char token_string[PATTERN_MAX_ARGS][PATTERN_BUFFER_SIZE]; //逐个字符串
char token_operator[PATTERN_MAX_ARGS]; //>,<,,=等等
int token_numeric[PATTERN_MAX_ARGS]; //一些数字
char buffer[PARSER_BUFFER_SIZE]; //工作缓冲
//一些错误测试
if( ( !string || strlen( string ) == 0 )|| ( !pattern || strlen( pattern ) == 0 ) )
return 0;
//将行拷贝进工作区域
strcpy( buffer, string );
int tok_start = 0,
tok_end = 0,
tok_restart = 0,
tok_first_pass = 0,
num_tokens = 0;
//第一步,消除列表
while( 1 )
{
//消除空格
while( isspace( pattern[tok_start] ) )
tok_start ++;
//行结束了么?
if( tok_start >= strlen( pattern ) )
break;
//寻找开始匹配'['
if( pattern[tok_start] == '[' )
{
//现在开始寻找匹配字符
switch( pattern[tok_start + 1] )
{
case PATTERN_TOKEN_FLOAT: //浮点数
{
//确认匹配格式正确有'【'就有'】'
if( pattern[tok_start + 2] != ']' )
return 0;
//向前推动个
tok_start += 3;
//将类型中插入一个浮点数
token_type[num_tokens] = PATTERN_TOKEN_FLOAT;
strcpy( token_string[num_tokens], "" );
token_operator[num_tokens] = 0;
token_numeric[num_tokens] = 0;
num_tokens++;
#ifdef PARSER_DEBUG_ON
printf("\n浮点数寻找" );
#endif
}
break;
case PATTERN_TOKEN_INT: //整数
{
//确认匹配格式正确有'【'就有'】'
if( pattern[tok_start + 2] != ']' )
return 0;
//向前推动个
tok_start += 3;
//将类型中插入一个整数
token_type[num_tokens] = PATTERN_TOKEN_INT;
strcpy( token_string[num_tokens], "" );
token_operator[num_tokens] = 0;
token_numeric[num_tokens] = 0;
num_tokens++;
#ifdef PARSER_DEBUG_ON
printf("\n整数寻找" );
#endif
}
break;
case PATTERN_TOKEN_LITERAL: //Literal字符串
{
//向前推动个
tok_start += 2;
tok_end = tok_start;
//消除字符串
while( pattern[tok_end] != PATTERN_TOKEN_LITERAL )
tok_end++;
//确认匹配格式正确有'【'就有'】'
if( pattern[tok_end + 1] != ']' )
return 0;
//literal字符串从(tok_start到(tok_end-1)
memcpy( token_string[num_tokens], & pattern[tok_start], ( tok_end - tok_start ) );
token_string[num_tokens][( tok_end - tok_start)] = 0;
//将类型中插入一个整数
token_type[num_tokens] = PATTERN_TOKEN_LITERAL;
token_operator[num_tokens] = 0;
token_numeric[num_tokens] = 0;
#ifdef PARSER_DEBUG_ON
printf("\n找到的LITERAL字符串=%s", token_string[num_tokens] );
#endif
tok_start = tok_end + 2;
num_tokens++;
}
break;
case PATTERN_TOKEN_STRING: //变长ASCII字符串
{
if( pattern[tok_start + 2] == '=' || pattern[tok_start + 2] == '>' || pattern[tok_start + 2] == '<' )
{
tok_end = tok_start + 3;
while( isdigit( pattern[tok_end] ) )
tok_end++;
//确认匹配格式正确有'【'就有'】'
if( pattern[tok_end ] != ']' )
return 0;
//ASCII字符串拷贝,兵转换为实数
memcpy( buffer, & pattern[tok_start + 3], ( tok_end - tok_start ) );
buffer[tok_end - tok_start] = 0;
//将类型中插入一个字符串
token_type[num_tokens] = PATTERN_TOKEN_STRING;
strcpy( token_string[num_tokens], "" );
token_operator[num_tokens] = pattern[tok_start + 2];
token_numeric[num_tokens] = atoi( buffer );
#ifdef PARSER_DEBUG_ON
printf("\n找到的字符串comparator=%s, characters: %d", token_operator[num_tokens], token_numeric[num_tokens] );
#endif
tok_start = tok_end + 1;
num_tokens++;
}
break;
default:
break;
}
}
if( tok_start >= strlen( pattern ) )
break;
}
#ifdef PARSER_DEBUG_ON
printf( "\n 字符串:%s", string );
printf( "\n扫描类型:%s", pattern );
printf( "\n数目:%d",num_tokens );
#endif
//此时,我们有了需要寻找的类型,于是寻找之
int pattern_state = PATTERN_STATE_INIT; //初始状态
int curr_tok = 0;
char token[PATTERN_BUFFER_SIZE];
//输入扫描状态机
while( 1 )
{
switch( pattern_state )
{
case PATTERN_STATE_INIT:
{
//模式初始状态
strcpy( buffer, string );
tok_start = 0;
tok_end = 0;
tok_restart = 0;
tok_first_pass = 1;
curr_tok = 0;
//重置输出队列
num_pints = num_pfloats = num_pstrings = 0;
//专项重置状态
pattern_state = PATTERN_STATE_RESTART;
}
break;
case PATTERN_STATE_RESTART:
{
curr_tok = 0;
tok_first_pass = 1;
//错误检测
if( tok_end >= strlen( buffer ) )
return 0;
//重置扫描器
tok_start = tok_end = tok_restart;
pattern_state = PATTERN_STATE_NEXT;
}
break;
case PATTERN_STATE_NEXT:
{
//看看匹配字符串是否已经匹配
if( curr_tok >= num_tokens )
{
pattern_state = PATTERN_STATE_MATCH;
}
else
{
if( tok_end >= strlen( buffer ) )
return ( 0 );
tok_start = tok_end;
while( isspace( buffer[tok_start] ) )
tok_start++;
tok_end = tok_start;
while( !isspace( buffer[tok_end] ) && tok_end < strlen( buffer ) )
tok_end++;
//
memcpy( token, & buffer[tok_start], tok_end - tok_start );
token[tok_end - tok_start] = 0;
if( strlen( token ) == 0 )
return ( 0 );
//
if( tok_first_pass )
{
tok_first_pass = 0;
tok_restart = tok_end;
}
//设置状态
switch( token_type[curr_tok] )
{
case PATTERN_TOKEN_FLOAT:
{
pattern_state = PATTERN_STATE_FLOAT;
}
break;
case PATTERN_TOKEN_INT:
{
pattern_state = PATTERN_STATE_INT;
}
break;
case PATTERN_TOKEN_STRING:
{
pattern_state = PATTERN_STATE_STRING;
}
break;
case PATTERN_TOKEN_LITERAL:
{
pattern_state = PATTERN_STATE_LITERAL;
}
break;
default:
break;
}
}
}
break;
case PATTERN_STATE_FLOAT:
{
float f = IsFloat( token );
if( f != FLT_MIN )
{
pfloats[num_pfloats++] = f;
curr_tok++;
pattern_state = PATTERN_STATE_NEXT;
}
else
{
pattern_state = PATTERN_STATE_RESTART;
}
}
break;
case PATTERN_STATE_INT:
{
int i = isInt( token );
if( i != INT_MIN )
{
pints[num_pints++] = i;
curr_tok++;
pattern_state = PATTERN_STATE_NEXT;
}
else
{
pattern_state = PATTERN_STATE_RESTART;
}
}
break;
case PATTERN_STATE_LITERAL:
{
if( strcmp( token, token_string[curr_tok] ) == 0 )
{
strcpy( pstrings[num_pstrings++], token );
curr_tok++;
pattern_state = PATTERN_STATE_NEXT;
}
else
{
pattern_state = PATTERN_STATE_RESTART;
}
}
break;
case PATTERN_STATE_STRING:
{
//需要测试非空字符
switch( token_operator[curr_tok] )
{
case '=':
{
if( strlen( token ) == token_numeric[curr_tok] )
{
strcpy( pstrings[num_pstrings++], token );
curr_tok++;
pattern_state = PATTERN_STATE_NEXT;
}
else
{
pattern_state = PATTERN_STATE_RESTART;
}
}
break;
case '>':
{
if( strlen( token ) > token_numeric[curr_tok] )
{
strcpy( pstrings[num_pstrings++], token );
curr_tok++;
pattern_state = PATTERN_STATE_NEXT;
}
else
{
pattern_state = PATTERN_STATE_RESTART;
}
}
break;
case '<':
{
if( strlen( token ) < token_numeric[curr_tok] )
{
strcpy( pstrings[num_pstrings++], token );
curr_tok++;
pattern_state = PATTERN_STATE_NEXT;
}
else
{
pattern_state = PATTERN_STATE_RESTART;
}
}
break;
default:
break;
}
}
break;
case PATTERN_STATE_MATCH:
{
#ifdef PARSER_DEBUG_ON
printf( "\n模式:%s匹配!", pattern );
#endif
return ( 1 );
}
break;
case PATTERN_STATE_END:
{
}
break;
default:
break;
}
}
}
//设定模式匹配的内存空间和数量
#define PATTERN_BUFFER_SIZE 80
#define PATTERN_MAX_ARGS 16
万事俱备,现在进行模式匹配。