3

我有一些使用文本文件的 C# 代码,我似乎无法让它与空白或空(空白)行一起正常工作。

我的代码:

        while (!file.EndOfStream)
        {
            line = file.ReadLine();

            bool isComment = (line[0] == '/') && (line[1] == '/');
            bool isPoint = (line[0] == '(') && (line[line.Length - 1] == ')');
            bool isWhiteSpace = string.IsNullOrEmpty(line);

            Debug.Log("Comment: " + isComment + ", Point: " + isPoint + ", WhiteSpace: " + isWhiteSpace + "Value: '" + line + "'");

            if (!isComment && !isPoint && !isWhiteSpace) { Application.Quit(); }
            else if (isPoint)
            {
                //Strip parenthesis
                line = line.Remove(line.Length - 1, 1).Remove(0, 1);

                //break into float array
                string[] arr = line.Split(',');

                float xVal = float.Parse(arr[0]);
                float yVal = float.Parse(arr[1]);
                float zVal = float.Parse(arr[2]);

                Vector3 currentVector = new Vector3(xVal, yVal, zVal);
                results.Add(currentVector);
            }
        }

你可以看到我恰好在用 Vector3 做事。如果该行是注释行或空白行,我希望它什么也不做。如果它注意到括号,我希望它假设它是一个 Vector3 并解析它。最后,如果它不是这些线,我希望它完全停止。这是我仅使用记事本创建的示例文本文件:

//This is a comment
// ... and so is this!
(0, -1.5, 3)
(1, 4, 1.23)

(3, 5, 2)

请注意,第二个和第三个 Vector3 之间存在间隙。在这种特殊情况下,该行完全为空,不包含空格或任何内容,我只需在记事本中按 [Enter][Enter]。当我的脚本到达这一行时,它似乎触发了 file.EndOfStream boolean.... 但它不是文件的结尾!我怎样才能解决这个问题?我的 while 循环是否有更合适的条件?我还尝试读取该行并检查它是否为 null 作为 while 条件,这是一种更流行的处理方法,但这种处理方式也不适用于我的情况。

** 注意:“file”是 StreamReader 类型的变量 **

4

2 回答 2

8

这更像是一个风格说明而不是一个答案,尽管这也可以防止你看到的问题。

首先,StreamReader当您调用时,ReadLine您只会null在到达文件末尾时收到结果。您也不关心行首和行尾的空格,并且大概也不关心完全是空格的行。所以你可以用它来测试文件结尾和空行:

string line;
while ((line = file.ReadLine()) != null)
{
    line = line.Trim();
    if (line == "")
        continue;
}

接下来,您对开始/结束字符进行了一些测试,这些字符在某些情况下仍会导致问题。具体来说,读取一行中只有一个字符的第二个字符会导致异常。

StartsWith您可以使用andEndsWith方法进行测试,而不是对未经测试长度的字符串使用索引:

bool isComment = line.StartsWith("//");
bool isPoint = line.StartsWith("(") && line.EndsWith(")");

最后,在解析点值的代码中,假设任何以开头(和结尾的行都)至少包含 2 个逗号,并且文本将正确解析。这是一个不好的假设。

处理所有这一切的更好方法是随时检测和处理每种情况,将解析功能分解为可以重用的方法

这是我的版本:

public class Program
{
    public static void Main()
    {
        List<Vector3> results = new List<Vector3>();
        using (var file = System.IO.File.OpenText(@"C:\temp\test.txt"))
        {
            string line;
            while ((line = file.ReadLine()?.Trim()) != null)
            {
                // skip empty lines and comments
                if (line == string.Empty || line.StartsWith("//"))
                    continue;
                // parse all other lines as vectors, exit program on error
                try
                {
                    Vector3 vector = ParseVector(line);
                    results.Add(vector);
                }
                catch (FormatException e)
                {
                    Console.WriteLine("Parse error on line: {0}", line);
                    throw;
                }
            }
        }

        foreach (var v in results)
            Console.WriteLine("({0},{1},{2})", v.X, v.Y, v.Z);
    }

    // parse string in format '(x,y,z)', all as floats
    // throws FormatException on any error
    public static Vector3 ParseVector(string text)
    {
        if (!text.StartsWith("(") || !text.EndsWith(")"))
            throw new FormatException();
        string[] parts = text.Substring(1, text.Length - 1).Split(',');
        if (parts.Length != 3)
            throw new FormatException();
        float x = float.Parse(parts[0]);
        float y = float.Parse(parts[1]);
        float z = float.Parse(parts[2]);
        return new Vector3(x, y, z);
    }
}

如果您不想使用异常,则可以返回 null 或使用TryParse方法使用的模式,返回布尔成功/失败指示符并使用out参数将结果写入。在这种情况下,我更喜欢例外。

于 2015-11-30T00:01:08.853 回答
0

大卫是对的。我正在达到索引越界异常。以下是我更正且有效的代码:

        while (!file.EndOfStream)
        {
            line = file.ReadLine();

            bool isWhiteSpace = false;
            bool isComment = false;
            bool isPoint = false;

            isWhiteSpace = string.IsNullOrEmpty(line);

            if (!isWhiteSpace)
            {
                isComment = (line[0] == '/') && (line[1] == '/');
                isPoint = (line[0] == '(') && (line[line.Length - 1] == ')');
            }
            Debug.Log("Comment: " + isComment + ", Point: " + isPoint + ", WhiteSpace: " + isWhiteSpace + "Value: '" + line + "'");

            if (!isComment && !isPoint && !isWhiteSpace) { Application.Quit(); }
            else if (isPoint)
            {
                //Strip parenthesis
                line = line.Remove(line.Length - 1, 1).Remove(0, 1);

                //break into float array
                string[] arr = line.Split(',');

                float xVal = float.Parse(arr[0]);
                float yVal = float.Parse(arr[1]);
                float zVal = float.Parse(arr[2]);

                Vector3 currentVector = new Vector3(xVal, yVal, zVal);
                results.Add(currentVector);
            }
        }
于 2015-11-29T23:20:08.800 回答