首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >检查字符串是否可以解析的最快方法

检查字符串是否可以解析的最快方法
EN

Stack Overflow用户
提问于 2013-05-30 20:09:51
回答 5查看 11.3K关注 0票数 19

我正在将CSV文件解析为具有强类型属性的对象列表。这涉及到使用IConvertible将文件中的每个字符串值解析为decimal类型(intdecimaldoubleDateTime等)。

我使用try catch来处理解析失败的情况。然后记录此异常发生的位置和原因的确切详细信息,以供进一步调查。以下是实际的解析代码:

代码语言:javascript
复制
try
{
    parsedValue = TypeDescriptor.GetConverter(type).ConvertFromString(dataValue);
}
catch (Exception ex)
{
    // Log failure
}

问题:

当值被成功解析时,这个过程会很快。当解析包含大量无效数据的数据时,该过程可能会慢数千倍(由于捕获了异常)。

我一直在通过解析DateTime来测试这一点。以下是性能数据:

  • 成功解析: average of 32 ticks per parse
  • Failed parsing: average of 146296 ticks per parse

这比以前慢了4500倍。

问题:

是否可以检查字符串值是否可以成功解析,而不必使用代价高昂的try catch方法?或者,也许我应该用另一种方式来做这件事?

编辑:我需要使用 DateTime.TryParse**) (而不是DateTime.TryParse**),因为类型是在运行时确定的。**

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-05-30 20:50:17

如果您有一组已知的类型要转换,您可以执行一系列的if/elseif/elseif/else (或类型名上的switch/case ),从本质上将其分发给专门的解析方法。这应该是相当快的。这与@Fabio's answer中的描述相同。

如果您仍然有性能问题,您还可以创建一个查找表,它允许您在需要支持新解析方法时添加它们:

给定一些基本的解析包装器:

代码语言:javascript
复制
public delegate bool TryParseMethod<T>(string input, out T value);

public interface ITryParser
{
    bool TryParse(string input, out object value);
}

public class TryParser<T> : ITryParser
{
    private TryParseMethod<T> ParsingMethod;

    public TryParser(TryParseMethod<T> parsingMethod)
    {
        this.ParsingMethod = parsingMethod;
    }

    public bool TryParse(string input, out object value)
    {
        T parsedOutput;
        bool success = ParsingMethod(input, out parsedOutput);
        value = parsedOutput;
        return success;
    }
}

然后,您可以设置一个转换助手,它执行查找并调用适当的解析器:

代码语言:javascript
复制
public static class DataConversion
{
    private static Dictionary<Type, ITryParser> Parsers;

    static DataConversion()
    {
        Parsers = new Dictionary<Type, ITryParser>();
        AddParser<DateTime>(DateTime.TryParse);
        AddParser<int>(Int32.TryParse);
        AddParser<double>(Double.TryParse);
        AddParser<decimal>(Decimal.TryParse);
        AddParser<string>((string input, out string value) => {value = input; return true;});
    }

    public static void AddParser<T>(TryParseMethod<T> parseMethod)
    {
        Parsers.Add(typeof(T), new TryParser<T>(parseMethod));
    }

    public static bool Convert<T>(string input, out T value)
    {
        object parseResult;
        bool success = Convert(typeof(T), input, out parseResult);
        if (success)
            value = (T)parseResult;
        else
            value = default(T);
        return success;
    }

    public static bool Convert(Type type, string input, out object value)
    {
        ITryParser parser;
        if (Parsers.TryGetValue(type, out parser))
            return parser.TryParse(input, out value);
        else
            throw new NotSupportedException(String.Format("The specified type \"{0}\" is not supported.", type.FullName));
    }
}

那么用法可能是这样的:

代码语言:javascript
复制
//for a known type at compile time
int value;
if (!DataConversion.Convert<int>("3", out value))
{
    //log failure
}

//or for unknown type at compile time:
object value;
if (!DataConversion.Convert(myType, dataValue, out value))
{
    //log failure
}

这可能会扩展泛型以避免object装箱和类型转换,但就目前而言,它工作得很好;也许只有当您有可测量的性能时,才会优化这一方面。

编辑:您可以更新DataConversion.Convert方法,以便如果它没有注册指定的转换器,它可以回退到您的TypeConverter方法或抛出适当的异常。如果你想要一个通用的或者仅仅是你的预定义的一组支持的类型,而不是让你的try/catch重来,这取决于你。现在,代码已经更新,抛出了一个NotSupportedException,其中包含一条指示不受支持类型的消息。请随意调整,因为这是有意义的。就性能而言,也许这样做是有意义的,因为一旦您为最常用的类型指定了专门的解析器,这些解析器可能会变得很少。

票数 13
EN

Stack Overflow用户

发布于 2013-05-30 20:15:59

如果您知道要解析的类型,则使用TryParse方法:

代码语言:javascript
复制
String value;
Int32 parsedValue;
if (Int32.TryParse(value, parsedValue) == True)
    // actions if parsed ok
else
    // actions if not parsed

其他类型也是如此

代码语言:javascript
复制
Decimal.TryParse(value, parsedValue)
Double.TryParse(value, parsedValue)
DateTime.TryParse(value, parsedValue)

或者,您可以使用下一个解决方法:

为每个具有相同名称但签名不同的类型创建一个解析方法(将TryParse包装在其中):

代码语言:javascript
复制
Private bool TryParsing(String value, out Int32 parsedValue)
{
    Return Int32.TryParse(value, parsedValue)
}

Private bool TryParsing(String value, out Double parsedValue)
{
    Return Double.TryParse(value, parsedValue)
}

Private bool TryParsing(String value, out Decimal parsedValue)
{
    Return Decimal.TryParse(value, parsedValue)
}

Private bool TryParsing(String value, out DateTime parsedValue)
{
    Return DateTime.TryParse(value, parsedValue)
}

然后,您可以对类型使用方法TryParsing

票数 6
EN

Stack Overflow用户

发布于 2013-05-30 20:11:47

您可以使用TryParse方法:

代码语言:javascript
复制
if (DateTime.TryParse(input, out dateTime))
{
    Console.WriteLine(dateTime);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16835750

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档