字符串怎么转换成正则表达式 字符串

承上篇的思路继续写,这次介绍字符串转 Type 的方式——类型分析。我的思路是把 Type 解析由“TestNet.Person, TestNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null” 这种复杂的方式改为 “Person” 这种。这样,写起来简单明了,看起来也简单明了。
这次要说的东西比较简单,我借用一个例子说明:
首先,字符串“TestNet.Person”经过解析被分析为下面的 Token 集合:
标识、索引值 = 0、文本表示 = TestNet
句点、索引值 = 7、文本表示 = .
标识、索引值 = 8、文本表示 = Person
接着,判断标识符是否等于 int、bool 等 C# 基本类型文本名称,是则返回相应的类型( Type 实例);否则借用 Type.GetType 方法解析,进一步借用 Assembly.GetType 方法解析:
判断 TestNet 不是 int、bool 等 C# 基本类型的文本名称。
借用 Type.GetType 方法解析,返回值为 null 。
进一步借用 Assembly.GetType 方法解析,返回值为 null 。
读取下一个字符 ID = 句点,表示 TestNet 可能是命名空间名称,需要继续读取并分析。
判断 TestNet.Person 不是 int、bool 等 C# 基本类型的文本名称。
借用 Type.GetType 方法解析,返回值为 null 。
进一步借用 Assembly.GetType 方法解析,返回值为 TestNet.Person 类型的 Type 实例。
分析过程结束。
实际的过程中,我们还需要为分析方法添加额外的命名空间。这样,像“TestNet.Person” 这样的类型,就可以简写为 “Person”,符合我们使用 C# 的编码规范。
进一步考虑,我们可以从项目未引用的程序集中提取类型,这时候需要添加额外的 Assembly 。这样做的好处是:可以在不编译整个项目的情况下,更改某个配置,就可以使用新的程序集,新的逻辑。呵呵,是不是有点插件式编程的影子了。下一篇,应该会揭开面纱了。
下面,我给出类型解析类(TypeParser)的源码:
/// &summary&
/// 类型分析器
/// &/summary&
[DebuggerStepThrough]
public class TypeParser
#region Properties
/// &summary&
/// 原始字符串分析结果
/// &/summary&
private SymbolParseResult spResult = null;
/// &summary&
/// 获得待分析的类型可能用到的命名空间列表
/// &/summary&
private IEnumerable&string& namespaces = Enumerable.Empty&string&();
/// &summary&
/// 获得额外的程序集信息列表
/// &/summary&
private IEnumerable&Assembly& assemblyExtensions = Enumerable.Empty&Assembly&();
private TypeParser()
/// &summary&
/// Initializes a new instance of the &see cref=&TypeParser&/& class.
/// &/summary&
/// &param name=&spResult&&The symbol parse result.&/param&
internal TypeParser(ref SymbolParseResult spResult)
this.spResult = spR
/// &summary&
/// 获得一个 &see cref=&TypeParser&/& 类的实例对象
/// &/summary&
public static TypeParser NewInstance
get { return new TypeParser(); }
private static Assembly[] _assemblies = null;
/// &summary&
/// 获取程序入口点所在目录程序集列表
/// &/summary&
private static Assembly[] Assemblies
if (_assemblies == null)
var directory = string.E
var assembly = Assembly.GetEntryAssembly();
if (assembly != null)
directory = Path.GetDirectoryName(assembly.Location);
directory = AppDomain.CurrentDomain.BaseD
var files = Directory.GetFiles(directory, &*.dll&, SearchOption.TopDirectoryOnly);
var data = new List&Assembly&(files.Length);
foreach (var item in files)
data.Add(Assembly.LoadFile(item));
_assemblies = data.ToArray();
#endregion
#region Business Methods
/// &summary&
/// 添加可能遇到的命名空间字符串列表
/// &/summary&
/// &param name=&namespaces&&新的命名空间字符串列表&/param&
/// &returns&修改后的自身&/returns&
public TypeParser SetNamespaces(IEnumerable&string& namespaces)
this.namespaces = namespaces ?? Enumerable.Empty&string&();
return this;
/// &summary&
/// 添加可能遇到的命名空间字符串列表
/// &/summary&
/// &param name=&namespaces&&新的命名空间字符串列表&/param&
/// &returns&修改后的自身&/returns&
public TypeParser SetNamespaces(params string[] namespaces)
this.namespaces = namespaces ?? Enumerable.Empty&string&();
return this;
/// &summary&
/// 添加可能遇到的程序集信息列表
/// &/summary&
/// &param name=&assemblies&&附加的程序集信息列表&/param&
/// &returns&修改后的自身&/returns&
public TypeParser SetAssemblies(IEnumerable&Assembly& assemblies)
assemblyExtensions = assemblies ?? Enumerable.Empty&Assembly&();
return this;
/// &summary&
/// 添加可能遇到的程序集信息列表
/// &/summary&
/// &param name=&assemblies&&附加的程序集信息列表&/param&
/// &returns&修改后的自身&/returns&
public TypeParser SetAssemblies(params Assembly[] assemblies)
assemblyExtensions = assemblies ?? Enumerable.Empty&Assembly&();
return this;
/// &summary&
/// 解析字符串为类型
/// &/summary&
/// &returns&读取的类型&/returns&
public Type Resolve(string typeString)
spResult = SymbolParser.Build(typeString);
return ReadType();
#endregion
#region Private Methods
internal Type ReadType(string typeName = null, bool ignoreException = false)
Type type = null;
StringBuilder sbValue =
new StringBuilder(string.IsNullOrEmpty(typeName) ? spResult.Next() : typeName);
// read generic parameters
if (spResult.PeekNext() == &&&)
spResult.Skip();
List&Type& listGenericType = new List&Type&();
while (true)
listGenericType.Add(ReadType());
if (spResult.PeekNext() == &,&)
spResult.Skip();
NextIsEqual(&&&);
sbValue.AppendFormat(&`{0}[{1}]&, listGenericType.Count,
string.Join(&,&, listGenericType
.Select(p =& &[& + p.AssemblyQualifiedName + &]&).ToArray()));
type = GetType(sbValue.ToString());
if (type == null)
bool result = NextIsEqual(&.&, false);
if (!result)
if (ignoreException)
throw new ParseUnfindTypeException(sbValue.ToString(), spResult.Index);
sbValue.Append(&.&);
sbValue.Append(spResult.Next());
} while (type == null);
internal Type GetType(string typeName)
if (string.IsNullOrEmpty(typeName))
return null;
// Nullable
bool isNullable = false;
if (typeName.EndsWith(&?&))
isNullable = true;
typeName = typeName.Substring(0, typeName.Length - 1);
switch (typeName)
case &bool&:
type = typeof(bool);
case &byte&:
type = typeof(byte);
case &sbyte&:
type = typeof(sbyte);
case &char&:
type = typeof(char);
case &decimal&:
type = typeof(decimal);
case &double&:
type = typeof(double);
case &float&:
type = typeof(float);
case &int&:
type = typeof(int);
case &uint&:
type = typeof(uint);
case &long&:
type = typeof(long);
case &ulong&:
type = typeof(ulong);
case &object&:
type = typeof(object);
case &short&:
type = typeof(short);
case &ushort&:
type = typeof(ushort);
case &string&:
type = typeof(string);
// Suppose typeName is full name of class
type = GetTypeCore(typeName);
// Did not find the namespace to use all of the match again and again
if (type == null)
foreach (string theNamespace in namespaces)
type = GetTypeCore(string.Concat(theNamespace, &.&, typeName));
// To find a qualified first class
if (type != null)
if (isNullable && type != null)
type = typeof(Nullable&&).MakeGenericType(type);
private Type GetTypeCore(string typeName)
Type type = Type.GetType(typeName);
if (type != null)
Assembly[] listAssembly = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in listAssembly)
type = assembly.GetType(typeName, false, false);
if (type != null)
if (assemblyExtensions != null && assemblyExtensions.Any())
foreach (Assembly assembly in assemblyExtensions)
type = assembly.GetType(typeName, false, false);
if (type != null)
if (Assemblies != null && Assemblies.Any())
foreach (Assembly assembly in Assemblies)
type = assembly.GetType(typeName, false, false);
if (type != null)
return null;
private bool NextIsEqual(string symbol, bool throwExceptionIfError = true)
if (spResult.Next() != symbol)
if (throwExceptionIfError)
throw new ApplicationException(string.Format(&{0} isn't the next token&, symbol));
return false;
return true;
#endregion
使用到的一个异常类如下:
/// &summary&
/// Parse UnfindType Exception
/// &/summary&
[Serializable]
[DebuggerStepThrough]
public class ParseUnfindTypeException : Exception
/// &summary&
/// Initializes a new instance of the &see cref=&ParseUnfindTypeException&/& class.
/// &/summary&
/// &param name=&typeName&&Name of the type.&/param&
/// &param name=&errorIndex&&Index of the error.&/param&
public ParseUnfindTypeException(string typeName, int errorIndex)
: base(string.Format(&{0} in the vicinity of the type \&{1}\& not found&, errorIndex, typeName))
需要注意的是,这个类用到了上次提到的字符串解析结果,需要两者相互配合。嘿嘿,再给个示意图诱惑一下:
如果您感觉有用,顺手点下推荐,谢了!
阅读(...) 评论()2011年4月 .NET技术大版内专家分月排行榜第二
2011年3月 .NET技术大版内专家分月排行榜第三
2011年4月 .NET技术大版内专家分月排行榜第二
2011年3月 .NET技术大版内专家分月排行榜第三
2010年 总版技术专家分年内排行榜第一2009年 总版技术专家分年内排行榜第一
2011年 总版技术专家分年内排行榜第二
2011年4月 .NET技术大版内专家分月排行榜第二
2011年3月 .NET技术大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。共有 6984 人关注过本帖
标题:怎样将字符串中的表达式计算出来?
等 级:新手上路
&&问题点数:0&&回复次数:13&&&
怎样将字符串中的表达式计算出来?
输入一字符串,如&10+20-25&,要怎么做才能计算出他的值。
也就是说怎样将字符串转换成表达式?
[[it] 本帖最后由 ramble55 于
23:02 编辑 [/it]]
搜索更多相关主题的帖子:
等 级:新手上路
帖 子:87
&&&int a=10,b=20,c=25;
&&&printf(&%d&,a+b-c);
等 级:新手上路
帖 子:87
可以用atoi将代表数字的字符串转换成int的数
等 级:新手上路
我晕,是字符串&a+b+c&,不是直接命名整型+起来
等 级:新手上路
atoi是可以转换数字,但是运算符加号减号这些呢?
等 级:贵宾
威 望:29
帖 子:3607
专家分:1709
回复 6# 的帖子
检测一下字符串,如果遇到运算符号,就存到一个数组里,如果遇到字符,就换算成整数,存到另一个数组里,然后再把它们之间进行运算,就可以了。
&&& 说着简单,做着不容易。你可以在论坛里翻看,我记着前两天还有人发了关于记算器的代码,你的这个问题在那里应该能得到答案。或者到百度搜一下,应该有很多。
等 级:新手上路
帖 子:374
稍微扩充了一下,用纯C改写了……没想到一下子这么大了……
程序代码:
#include &stdio.h&
#include &string.h&
#include &ctype.h&
/* 堆栈大小 */
#define STACK_MAX 100
/* 要求double达到的精度 */
#define IS_DOUBLE_ZERO(d)&&((d) & 0. && (d) & -0.)
/* 助手宏,检查当前堆栈包含元素数量 */
#define GET_STACK_SIZE(stack) (stack##_stack_top - stack##_stack + 1)
/* 助手宏,用于检查堆栈是否为空 */
#define IS_STACK_EMPTY(stack) (GET_STACK_SIZE(stack) &= 0)
/* 助手宏,用于检查堆栈是否已满 */
#define CHECK_STACK_OVERFLOW(stack) \
&&&&&&&&&&&&if (GET_STACK_SIZE(stack) &= STACK_MAX) \
&&&&&&&&&&&&&&& return STATUS_STACK_OVERFLOW
/* 助手宏,用于每次的堆栈计算 */
#define CALC_OPT_IN_STACK() \
&&&&&&&&&&&&{ \
&&&&&&&&&&&&&&& int ret = calc_opt_with_stack(opt_stack, &opt_stack_top, \
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& num_stack, &num_stack_top); \
&&&&&&&&&&&&&&&&&&&&&&&&if (ret != STATUS_OK) \
&&&&&&&&&&&&&&&&&&&&&&&&&&& \
&&&&&&&&&&&&}
/* 状态枚举,由主函数及StackCalc返回 */
typedef enum status_type
&&& STATUS_OK&&&&&&&&&&&&&&& = 0, /* 正常返回&&&*/
&&& STATUS_DIV_BY_ZERO&&&&&& = 1, /* 被零除&&&&&*/
&&& STATUS_NUMBER_ERROR&&&&&&= 2, /* 操作数错误 */
&&& STATUS_OPTERATOR_ERROR&&&= 3, /* 运算符错误 */
&&& STATUS_INVALID_TOKEN&&&&&= 4, /* 非法字符&&&*/
&&& STATUS_STACK_OVERFLOW&&& = 5, /* 堆栈溢出&&&*/
} status_t;
&* 取得一元运算符,若opt_in_stack不为NULL,比较栈外新式,并
&* 通过opt_in_stack返回栈外形式,否则,比较栈内形式。之所以
&* 分为两个形式是为了在堆栈内部区别加减号和正负号。
int is_unary_opt(char opt, char *opt_in_stack)
&&& /* TODO: 在下面对应的两个数组中添加自己的一元操作符 */
&&& static char *opt_list&&&&&&&&& = &+-&;
&&& static char *opt_in_stack_list = &s!&;
&&& if (opt_in_stack != NULL)
&&&&&&&&char *loc = strchr(opt_list, opt);
&&&&&&&&if (loc == NULL)
&&&&&&&&&&&&return 0;
&&&&&&&&*opt_in_stack = opt_in_stack_list[loc - opt_list];
&&&&&&&&return 1;
&&& return strchr(opt_in_stack_list, opt) != NULL;
&* 取得运算符优先级,如果不是运算符,则返回0,数字越大表示优
&* 先级越低
int get_bin_opt(char op)
&&& /* TODO: 在这里添加你自己的二元操作符 */
&&& switch (op)
&&& case '*':
&&& case '/':
&&&&&&&&return 1;
&&& case '+':
&&& case '-':
&&&&&&&&return 2;
&&& return 0;
/* 根据堆栈栈顶的操作数及运算符计算。 */
status_t calc_opt_with_stack(const char *opt_stack, char **opt_stack_top,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&const double *num_stack, double **num_stack_top)
&&& if (*opt_stack_top - opt_stack & 0)
&&&&&&&&return STATUS_OPTERATOR_ERROR;
&&& if (is_unary_opt(**opt_stack_top, NULL))
&&&&&&&&if (*num_stack_top - num_stack & 0)
&&&&&&&&&&&&return STATUS_NUMBER_ERROR;
&&&&&&&&/* TODO: 在这里添加你自己的一元运算符的计算方法 */
&&&&&&&&switch (**opt_stack_top)
&&&&&&&&case 's':
&&&&&&&&&&&&
&&&&&&&&case '!':
&&&&&&&&&&&&**num_stack_top = -**num_stack_
&&&&&&&&&&&&
&&&&&&&&default:
&&&&&&&&&&&&return STATUS_OPTERATOR_ERROR;
&&&&&&&&--*opt_stack_
&&&&&&&&return STATUS_OK;
&&& if (*num_stack_top - num_stack & 1)
&&&&&&&&return STATUS_NUMBER_ERROR;
&&& /* TODO: 在这里添加你的二元运算符的计算方法 */
&&& switch (**opt_stack_top)
&&& case '+':
&&&&&&&&(*num_stack_top)[-1] += **num_stack_
&&& case '-':
&&&&&&&&(*num_stack_top)[-1] -= **num_stack_
&&& case '*':
&&&&&&&&(*num_stack_top)[-1] *= **num_stack_
&&& case '/':
&&&&&&&&/* 被除数为0 */
&&&&&&&&if (**num_stack_top == 0)
&&&&&&&&&&&&return STATUS_DIV_BY_ZERO;
&&&&&&&&(*num_stack_top)[-1] /= **num_stack_
&&& default:
&&&&&&&&return STATUS_OPTERATOR_ERROR;
&&& --*opt_stack_
&&& --*num_stack_
&&& return STATUS_OK;
&* 运算主程序,将改变pos的指向,可以据此判断错误位置,如果解
&* 析成功,答案由ans返回。如果str_pos为空,安静地返回OK。
status_t do_calculate(const char ** str_pos, double *ans)
&&& /* 当前是否需要数字(比如操作符和括号后) */
&&& int now_need_num = 1;
&&& /* 操作数栈和符号栈 */
&&& double num_stack[STACK_MAX], *num_stack_top = num_stack - 1;
&&& char opt_stack[STACK_MAX], *opt_stack_top = opt_stack - 1;
&&& if (str_pos == NULL)
&&&&&&&&return STATUS_OK;
&&& while (**str_pos != '\0')
&&&&&&&&/* 如果为空白字符,直接忽略掉 */
&&&&&&&&if (isspace(**str_pos))
&&&&&&&&&&&&++*str_
&&&&&&&&/* 如果为数字,直接入栈 */
&&&&&&&&else if (isdigit(**str_pos) || **str_pos == '.')
&&&&&&&&&&&&/* 将读出的数字的个数 */
&&&&&&&&&&&&int read_
&&&&&&&&&&&&/* 如果当前不期待操作数,返回错误 */
&&&&&&&&&&&&if (!now_need_num)
&&&&&&&&&&&&&&& return STATUS_NUMBER_ERROR;
&&&&&&&&&&&&/* 读取浮点数字到栈顶 */
&&&&&&&&&&&&CHECK_STACK_OVERFLOW(num);
&&&&&&&&&&&&sscanf(*str_pos, &%lf%n&, ++num_stack_top, &read_size);
&&&&&&&&&&&&*str_pos += read_
&&&&&&&&&&&&/* 计算位于当前数字之前的一元操作符 */
&&&&&&&&&&&&while (!IS_STACK_EMPTY(opt)
&&&&&&&&&&&&&&&&&&&&&& is_unary_opt(*opt_stack_top, NULL))
&&&&&&&&&&&&&&& CALC_OPT_IN_STACK();
&&&&&&&&&&&&/* 不可连续出现两个数字 */
&&&&&&&&&&&&now_need_num = 0;
&&&&&&&&/* 如果为括号,直接进栈 */
&&&&&&&&else if (**str_pos == '(')
&&&&&&&&&&&&/* 这时应该是期待操作数的 */
&&&&&&&&&&&&if (!now_need_num)
&&&&&&&&&&&&&&& return STATUS_OPTERATOR_ERROR;
&&&&&&&&&&&&/* 括号入栈 */
&&&&&&&&&&&&CHECK_STACK_OVERFLOW(opt);
&&&&&&&&&&&&*++opt_stack_top = *(*str_pos)++;
&&&&&&&&&&&&/* 括号后允许出现数字 */
&&&&&&&&&&&&now_need_num = 1;
&&&&&&&&/* 如果为反括号,需要判断括号是否匹配 */
&&&&&&&&else if (**str_pos == ')')
&&&&&&&&&&&&/* 这时应该不期待操作数 */
&&&&&&&&&&&&if (now_need_num)
&&&&&&&&&&&&&&& return STATUS_OPTERATOR_ERROR;
&&&&&&&&&&&&/* 遇到反括号,持续出栈直到遇到相应括号 */
&&&&&&&&&&&&while (!IS_STACK_EMPTY(opt) && *opt_stack_top != '(')
&&&&&&&&&&&&&&& CALC_OPT_IN_STACK();
&&&&&&&&&&&&/*
&&&&&&&&&&&& * 如果找不到相应括号,出错返回。否则,括号出栈
&&&&&&&&&&&& * ,即消掉了一对括号
&&&&&&&&&&&& */
&&&&&&&&&&&&if (IS_STACK_EMPTY(opt))
&&&&&&&&&&&&&&& return STATUS_OPTERATOR_ERROR;
&&&&&&&&&&&&/* 括号出栈 */
&&&&&&&&&&&&--opt_stack_
&&&&&&&&&&&&/* 计算位于当前括号之前的一元操作符 */
&&&&&&&&&&&&while (!IS_STACK_EMPTY(opt)
&&&&&&&&&&&&&&&&&&&&&& is_unary_opt(*opt_stack_top, NULL))
&&&&&&&&&&&&&&& CALC_OPT_IN_STACK();
&&&&&&&&&&&&/* 迭代下一个字符 */
&&&&&&&&&&&&++*str_
&&&&&&&&&&&&/* 反括号后不允许出现数字 */
&&&&&&&&&&&&now_need_num = 0;
&&&&&&&&/* 其他情况 */
&&&&&&&&else
&&&&&&&&&&&&char ch = **str_
&&&&&&&&&&&&/* 如果为二元操作符 */
&&&&&&&&&&&&if (get_bin_opt(ch))
&&&&&&&&&&&&{
&&&&&&&&&&&&&&& /*
&&&&&&&&&&&&&&&&&* 如果不需要出现数字,并且操作符栈非空并且栈顶
&&&&&&&&&&&&&&&&&* 元素不是括号,并且栈顶元素的优先级高于当前运
&&&&&&&&&&&&&&&&&* 算符,就计算栈内的前一次运算。因为那次运
&&&&&&&&&&&&&&&&&* 算优先级比当前运算高,所以必须先计算。
&&&&&&&&&&&&&&&&&*/
&&&&&&&&&&&&&&& if (!now_need_num
&&&&&&&&&&&&&&&&&&&&&&&&&& !IS_STACK_EMPTY(opt)
&&&&&&&&&&&&&&&&&&&&&&&&&& get_bin_opt(*opt_stack_top) != 0
&&&&&&&&&&&&&&&&&&&&&&&&&& get_bin_opt(*opt_stack_top) &= get_bin_opt(ch))
&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&CALC_OPT_IN_STACK();
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& /* 如果需要数字,可以认为这时出现的是一元操作符 */
&&&&&&&&&&&&&&& else if (now_need_num)
&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&/*
&&&&&&&&&&&&&&&&&&&&&* 如果为一元操作符,则替换ch为操作符的栈内
&&&&&&&&&&&&&&&&&&&&&* 形式,否则,返回操作符错误。
&&&&&&&&&&&&&&&&&&&&&*/
&&&&&&&&&&&&&&&&&&&&if (!is_unary_opt(ch, &ch))
&&&&&&&&&&&&&&&&&&&&&&&&return STATUS_OPTERATOR_ERROR;
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& /* 操作符入栈 */
&&&&&&&&&&&&&&& CHECK_STACK_OVERFLOW(opt);
&&&&&&&&&&&&&&& *++opt_stack_top =
&&&&&&&&&&&&&&& /* 操作符后期待操作数 */
&&&&&&&&&&&&&&& now_need_num = 1;
&&&&&&&&&&&&}
&&&&&&&&&&&&/* 如果为一元操作符 */
&&&&&&&&&&&&else if (is_unary_opt(ch, &ch))
&&&&&&&&&&&&{
&&&&&&&&&&&&&&& /* 一元操作符应该出现在需要操作数的位置。 */
&&&&&&&&&&&&&&& if (!now_need_num)
&&&&&&&&&&&&&&&&&&&&return STATUS_OPTERATOR_ERROR;
&&&&&&&&&&&&&&& /* 一元操作符入栈 */
&&&&&&&&&&&&&&& CHECK_STACK_OVERFLOW(opt);
&&&&&&&&&&&&&&& *++opt_stack_top =
&&&&&&&&&&&&&&& /* 一元操作符后期待数字 */
&&&&&&&&&&&&&&& now_need_num = 1;
&&&&&&&&&&&&}
&&&&&&&&&&&&/* 其他情况,报符号错误 */
&&&&&&&&&&&&else
&&&&&&&&&&&&&&& return STATUS_INVALID_TOKEN;
&&&&&&&&&&&&/* 移动位置指针 */
&&&&&&&&&&&&++*str_
&&& /* 计算剩余的操作符 */
&&& while (!IS_STACK_EMPTY(opt))
&&&&&&&&CALC_OPT_IN_STACK();
&&& /* 如果操作数栈内还存有除结果以外的数字,出错。 */
&&& if (GET_STACK_SIZE(num) != 1)
&&&&&&&&return STATUS_NUMBER_ERROR;
&&& /* 返回计算结果 */
&&& if (ans != NULL)
&&&&&&&&*ans = *num_stack_
&&& return STATUS_OK;
/* 接口函数,处理输入输出,方便计算函数使用 */
void calculate(const char* str)
&&& const char *cur_pos =
&&& status_t ret = do_calculate(&cur_pos, &ans);
&&& if (ret == STATUS_OK)
&&&&&&&&if (ans & 1e8 || IS_DOUBLE_ZERO(ans - (int)ans))
&&&&&&&&&&&&printf(&结果:%.12g\n&, ans);
&&&&&&&&else
&&&&&&&&&&&&printf(&结果:%.12f\n&, ans);
&&& /* 处理错误 */
&&&&&&&&int error_pos = cur_pos - str, expr_len = strlen(str);
&&&&&&&&const char *str_prefix, *str_postfix, *str_
&&&&&&&&if (expr_len & 40 && error_pos & 20)
&&&&&&&&&&&&str_prefix = &... &;
&&&&&&&&&&&&str_show = cur_pos - 20;
&&&&&&&&&&&&error_pos = 7 + 4 + 20;
&&&&&&&&else
&&&&&&&&&&&&str_prefix = &&;
&&&&&&&&&&&&str_show =
&&&&&&&&&&&&error_pos += 7;
&&&&&&&&str_postfix = (expr_len - error_pos & 20 ? & ...& : &&);
&&&&&&&&fprintf(stderr, &表达式解析错误!\n位置:%s%.40s%s\n%*c\n&,
&&&&&&&&&&&&&&& str_prefix, str_show, str_postfix, error_pos, '^');
&&& fputs(&错误:&, stderr);
&&& switch (ret)
&&& case STATUS_OK:
&&& case STATUS_DIV_BY_ZERO:
&&&&&&&&fputs(&被零除&, stderr);
&&& case STATUS_NUMBER_ERROR:
&&&&&&&&fputs(&操作数错误&, stderr);
&&& case STATUS_OPTERATOR_ERROR:
&&&&&&&&fputs(&运算符错误&, stderr);
&&& case STATUS_INVALID_TOKEN:
&&&&&&&&fputs(&非法字符&, stderr);
&&& case STATUS_STACK_OVERFLOW:
&&&&&&&&fputs(&栈溢出(表达式太过复杂?)&, stderr);
&&& fputc('\n', stderr);
int main(void)
&&& char str[1001];
&&& puts(&简易计算器 制作:StarWing\n输入end退出本程序。&);
&&& while (printf(&& &), fgets(str, 1000, stdin) != NULL)
&&&&&&&&char *end = strchr(str, '\n');
&&&&&&&&if (end != NULL)
&&&&&&&&&&&&*end = '\0';
&&&&&&&&if (end != str)
&&&&&&&&&&&&if (!strcmp(str, &end&))
&&&&&&&&&&&&&&&
&&&&&&&&&&&&calculate(str);
&&& return 0;
/* cc_flags += -g */
那个错误提示是模仿JDK做的,个人非常喜欢~~~嘿嘿~
[[it] 本帖最后由 风居住的街道 于
08:09 编辑 [/it]]
来 自:本因坊
等 级:新手上路
帖 子:19
楼上是MJ??
等 级:新手上路
帖 子:100
回复 7# 的帖子
强悍啊!!其实我觉得这个题目用队列可能会简单很多
等 级:新手上路
回复 7# 的帖子
厉害啊!我知道要用堆栈,就是不知道怎么用/xiexie
拿回去做做看
版权所有,并保留所有权利。
Powered by , Processed in 0.032757 second(s), 9 queries.
Copyright&, BCCN.NET, All Rights ReservedAutohotkey 中文论坛 - 变量名、变量值 表达式 字符串、转义 V1.2
表达式:通过字符串来表示,被计算,返回其结果。
 如:表达式1+1的结果为2,表达式Variable(变量名)的结果为变量的值。
函数默认使用表达式,命令默认使用非表达式(原义字符串),关键字亦区分(如,If 表达式,Ifxxx 非表达式)
:=运算符:字符串做表达式计算,并将其计算结果赋值(表达式赋值);
=运算符:字符串赋值(字符串赋值)。
"=% ":字符串赋值转换为表达式赋值。
v1:=v0&&&&;0(字符串"v0"作为表达式被计算,其计算结果——值0,被赋值至变量v1,则v1的值为0)
v2=v0&&&&;v0(字符串"v0"被赋值至变量v2,则v2的值为字符串"v0")
v3=% v0&&&&;0(同v3:=v0)
%变量名%:当计算%变量名%时,变量名被解析(展开)为变量值:
在表达式赋值、字符串赋值中会进行如上计算。在字符串中不被计算。
v1:=1&&&&&&&&;值为数字1的变量
v2:="v1"&&&&;值为字符串"V1"的变量
v3:=v1&&&&&&&&;1(表达式赋值:v1→1)
v4:=%v2%&&&&;1(变量名解析:%v2%→表达式赋值:v1→1)
v5=% v1&&&&;1(同v5:=v1,参见v3:=v1)
v6=% %v2%&&&&;1(同v6:=%v2%,参见v4:=%v2%)
;结果演示:
&&&&r.="v" A_Index ":" v%A_Index% "`n"
MsgBox % r
展开字符串中的变量解析式(%变量名%)及转义序列:
转义序列:`是转义符,`x是对原义x的转义,`x称为转义序列。
 如:原义的字符n,经`n转义后变成换行符
;v0~v4均为普通字符串(其中的"%变量名%"不被计算),注释中为出展Transform,deref开后的结果。
v2:="%v1%"&&&&&&&&;1(字符串中的"%变量名%"不被计算)
v3=``&&&&;`(转义序列``表示原义的`)
v4:="%v1%+%v1%"&&&&;1+1(仅展开字符串,不进行表达式计算)
;结果演示:
&&&&Transform, OutputVar, deref, % v%A_Index%
&&&&r.=A_Index ". " v%A_Index% ":`n&& " OutputVar "`n`n"
MsgBox % Trim(r,"`n")
转义符、转义序列:手册索引#EscapeChar (及转义序列的说明)
(论坛Wiki)
(论坛帖子,排版有点问题)
本来不想写什么,写着就偏了。

我要回帖

更多关于 el表达式包含字符串 的文章

 

随机推荐