简体   繁体   English

如何正确处理C#中的空行,空行或空行

[英]How to properly handle blank, null, or empty lines in C#

I have some C# code that is working with a text file, and i can not seem to get it to work properly with blank or null (whitespace) lines. 我有一些正在处理文本文件的C#代码,但我似乎无法使它与空白或空(空格)行一起正常工作。

My code: 我的代码:

        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);
            }
        }

You can see that i happen to be doing things with Vector3. 您可以看到,我恰巧是使用Vector3做事的。 If the line is a comment line or a whitespace line, i want it to do nothing. 如果该行是注释行或空白行,我希望它什么也不做。 If it notices parentheses, i want it to assume it is a Vector3 and parse it. 如果注意到括号,我希望它假定它是一个Vector3并对其进行解析。 Finally, if it is a line that is none of these, i want it to stop entirely. 最后,如果不是一条线,我希望它完全停止。 Here is a sample text file that i have created just with Notepad: 这是我仅使用记事本创建的示例文本文件:

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

(3, 5, 2)

Notice that there is a gap between the second and third Vector3. 请注意,第二个Vector3和第三个Vector3之间存在间隙。 In this particular case, the line is completely empty, it does not contain spaces or anything, i simply pressed [Enter][Enter] in Notepad. 在这种特殊情况下,该行完全为空,不包含空格或任何东西,我只需在记事本中按[Enter] [Enter]。 When my script reaches this line, it seems to trigger the file.EndOfStream boolean.... but its NOT the end of the file! 当我的脚本到达这一行时,似乎触发了file.EndOfStream布尔值...。但它不是文件的结尾! How can i fix this? 我怎样才能解决这个问题? Is there a more appropriate condition for my while loop? 我的while循环是否有更合适的条件? I have also tried reading the line in and checking if it is null as the while condition, which is a more popular way to approach this, but this way of doing things also does not work for my case. 我还尝试读取该行并检查while条件是否为null,这是一种更流行的处理方式,但是这种处理方式也不适用于我的情况。

** Note: "file" is a variable of type StreamReader ** **注意:“文件”是StreamReader类型的变量**

This is more of a style note than an answer, although this also will prevent the issues you were seeing. 尽管这还可以防止出现您遇到的问题,但这更多的是样式说明,而不是答案。

First, with a StreamReader when you call ReadLine you will only receive a null result when you reach the end of the file. 首先,使用StreamReader调用ReadLine时,到达文件末尾时只会收到null结果。 You also don't care about whitespace at the start and end of your lines, and presumably don't care about lines that are entirely whitespace either. 您也不必关心行的开头和结尾处的空格,并且大概也不必关心完全是空格的行。 So you can use that to test for end of file and empty lines this way: 因此,您可以通过以下方式使用它来测试文件结尾和空行:

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

Next you have some tests for start/end characters that is still going to cause problems in some situations. 接下来,您将对开始/结束字符进行一些测试,这些测试在某些情况下仍然会引起问题。 Specifically, reading the second character in a line that has only one character is going to cause an exception. 具体来说,在只有一个字符的行中读取第二个字符将导致异常。

Instead of using indexing on a string of untested length you can use the StartsWith and EndsWith methods to do your tests: 您可以使用StartsWithEndsWith方法进行测试,而不是对未经测试的长度的字符串使用索引:

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

Finally, in your code that parses the point value you assume that any line that starts with ( and ends with ) will have at least 2 commas in it, and that the text will correctly parse. 最后,在你的代码解析点值,你认为是开头的任何行(和结尾)将至少有2个逗号它,该文本将正确解析。 This is a bad assumption. 这是一个错误的假设。

The better way to handle all of this is to detect and deal with each case as you go, with the parse functionality broken out to a method you can reuse 处理所有这些问题的更好方法是在进行过程中检测并处理每种情况,将解析功能分解为可重用的方法

Here's my version: 这是我的版本:

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);
    }
}

If you prefer not to use exceptions you could return null or use the pattern used by the TryParse methods, returning a boolean success/failure indicator and using an out parameter to write the results to. 如果不想使用异常,则可以返回null或使用TryParse方法使用的模式,返回布尔值成功/失败指示符,并使用out参数将结果写入其中。 I prefer exceptions in this case. 在这种情况下,我更喜欢例外。

David was correct. 大卫是正确的。 I was reaching an index out of bounds exception. 我正在到达索引超出范围的异常。 Below is my corrected and working code: 以下是我已更正且有效的代码:

        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);
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM