4

我编写了一个通用方法,将与StringStringBuilder参数一起使用。它返回参数中第二个单词的位置(单词可以用空格和换行符分隔)。对于使用[]andLength()的论点,我想不出比下面丑陋的代码更好的东西了。有没有更优雅的方法来做到这一点?

int PositionOfTheSecondWord<T>(T text) // T can be String or StringBuilder
{
    int pos = 0;
    int state = 0;
    char c;

    // Get length of the text
    // UGLY!
    int length = text is StringBuilder ? (text as StringBuilder).Length : (text as String).Length;

    while (pos <= length - 1)
    {
        // Get the next character
        // UGLY!
        c = text is StringBuilder ? (text as StringBuilder)[pos] : (text as String)[pos];

        if (c == ' ' || c == '\n') // space
        {
            if (state == 1)
                state = 2; // 2 means the space between the first and the second word has begun
        }
        else // a letter
            if (state == 0)
                state = 1; // 1 means the first word has begun
            if (state == 2)
                return pos;

        pos++;

    }

    return -1;

}

PS 我不能只为 String 参数编写一个函数并从 StringBuilder.ToString() 调用它,因为我的 StringBuilder 可能很大。

4

4 回答 4

4

我认为最好的方法是使用重载方法。例如:

int PostionOfTheSecondWord(string text)
{
    // Code optimized for strings.
}

int PostionOfTheSecondWord(StringBuilder text)
{
    // Code optimized for StringBuilder.
}

这将使您的代码更易于阅读和维护,并且性能会更好。

希望这对您的探索有所帮助。

于 2012-09-16T07:27:12.113 回答
1

根据您的方法的长度,这可能是多态性的一种情况:

如其他答案中所述,string彼此StringBuilder无关。因此,对它们使用相同方法的唯一机会是为这两种相关的类型创建包装器。

您可以使用您的方法定义一个包装器基类,如下所示:

public abstract class ScannableStringBase
{
    public abstract int Length { get; }

    public abstract char this[int index] { get; }

    public int PositionOfTheSecondWord()
    {
        int pos = 0;
        int state = 0;
        char c;

        int length = this.Length;

        while (pos <= length - 1)
        {
            c = this[pos];

            if (c == ' ' || c == '\n') // space
            {
                if (state == 1)
                    state = 2; // 2 means the space between the first and the second word has begun
            }
            else // a letter
                if (state == 0)
                    state = 1; // 1 means the first word has begun
                if (state == 2)
                    return pos;

            pos++;
        }

        return -1;

    }
}

从该类派生处理所需值类型的子类:

public class ScannableString : ScannableStringBase
{
    public ScannableString(string value)
    {
        this.stringValue = value;
    }

    private readonly string stringValue;

    public override int Length {
        get {
            return stringValue.Length;
        }
    }

    public override char this[int index] {
        get {
            return stringValue[index];
        }
    }
}

public class ScannableStringBuilder : ScannableStringBase
{
    public ScannableString(stringBuilder value)
    {
        this.stringBuilder = value;
    }

    private readonly string stringBuilder;

    public override int Length {
        get {
            return stringBuilder.Length;
        }
    }

    public override char this[int index] {
        get {
            return stringBuilder[index];
        }
    }
}

总结一下,你得到:

  • 没有代码重复,因为PositionOfTheSecondWord()在基类中只定义了一次。
  • 类型安全,因为您的PositionOfTheSecondWord()方法不能在除stringor之外的任何东西上调用StringBuilder
  • 可扩展性,因为如果您发现要支持第三种类型,您可以简单地从ScannableStringBase.

一个可能的缺点可能是您必须事先区分要在某处分析的类型,因此您可以决定是实例化 aScannableString还是 a ScannableStringBuilder

于 2012-09-16T08:12:53.837 回答
0
int GetPos(string text)
    {
        int length = text.Length;
        for (int i = 0; i < length; i++)
        {
            if (GetChar(text, i) == ' ')
            {
                return i;
            }
        }

        return -1;
    }

    int GetPos(StringBuilder sb)
    {
        int length = sb.Length;
        for (int i = 0; i < length; i++)
        {
            if (GetChar(sb, i) == ' ')
            {
                return i;
            }
        }

        return -1;
    }

    char GetChar<T>(T text, int pos)
    {
        if (text.GetType() == typeof(StringBuilder))
        {
            return (text as StringBuilder)[pos];
        }
        else if (text.GetType() == typeof(String))
        {
            return (text as String)[pos];
        }
        else
        {
            throw new ArgumentException("Wrong parameter, T must be string or StringBuilder");
        }
    }
于 2012-09-16T07:38:52.930 回答
0

如果你想使用一个泛型方法,你可以使用这个最简单的代码来达到同样的效果。

// T can be String or StringBuilder:
static int PositionOfTheSecondWordNew<T>(T text) 
{
    int pos = -1;
    string[] word;

    // If T is string or StringBuilder this line is not necessary:
    if ((text is StringBuilder) || (text is string)) 
    {
        word = text.ToString().Split(new char[]{' ', '\n'});
        pos = word[0].Length;
    }
    return pos;
}
于 2012-09-16T07:54:50.157 回答