【问题标题】:how to Tryparse Numbers from Text file like ascii art with c#?如何使用 c# 从文本文件(如 ascii 艺术)中尝试解析数字?
【发布时间】:2015-08-28 11:15:02
【问题描述】:

我怎样才能得到用棍子在 ascii 艺术中编码的数字?

数字在一个 txt 文件中,它包含以下内容:

我必须得到被棍子淹没的数字。

第一步是得到4行,然后用字母来控制它。

我得到一个字符串中的文本[]

string[] lines = File.ReadAllLines("SourceFile.txt");

前 4 行到第 [3] 行。 如何控制同一位置的不同线路? 它就像一个二维数组,还是我必须做其他事情?

【问题讨论】:

  • 每个数字都有其独特的模式不是吗?您可以计算行 [0] 中有多少次空格,然后查看第一行中有多少个数字。然后取第 0 到 4 行组成数字并用 5 再次计数
  • 既然你知道有多少个数字,你可以检查每个模式
  • @SamY 是的,每个数字都有其独特的模式。我怎样才能在代码中做你的逻辑? (用模式计数和控制?)
  • 您需要检查确切的代码,但是像 lines[0].split(" ").length 是拆分后第 1 行中有多少个数字,您必须检查一个模式在另一个之后,所以如果 [0] 的第一个模式是“---”,那么检查 [1] 的第一个模式是否是“/”,如果不是,则检查它是否是“_|”等等
  • 对于 \t 你需要进行第二次拆分

标签: c# winforms ascii-art


【解决方案1】:

首先,您需要一个对象来存储符号的模式和指标(在您的情况下为数字)。此对象还有一种方法可以在给定数组中识别其模式:

public class AsciiNumber
{
    private readonly char[][] _data;

    public AsciiNumber(char character, char[][] data)
    {
        this._data = data;
        this.Character = character;
    }

    public char Character
    {
        get;
        private set;
    }

    public int Width
    {
        get
        {
            return this._data[0].Length;
        }
    }

    public int Height
    {
        get
        {
            return this._data.Length;
        }
    }

    public bool Match(string[] source, int startRow, int startColumn)
    {
        if (startRow + this.Height > source.Length)
        {
            return false;
        }

        for (var i = startRow; i < startRow + this.Height; i++)
        { 
            var row = source[i];
            if (startColumn + this.Width > row.Length)
            {
                return false;
            }

            for (var j = startColumn; j < startColumn + this.Width; j++)
            {
                if (this._data[i - startRow][j - startColumn] != row[j])
                {
                    return false;
                }
            }
        }

        return true;
    }
}

然后你可以创建你处理的类似字母的东西(我只使用了数字 1 和 3):

public static class Alphabet
{
    private static readonly AsciiNumber Number1 = new AsciiNumber('1', new[]{
        new []{'|'},
        new []{'|'},
        new []{'|'},
        new []{'|'},
    });

    private static readonly AsciiNumber Number3 = new AsciiNumber('3', new[]{
        new []{'-','-','-'},
        new []{' ',' ','/'},
        new []{' ',' ','\\'},
        new []{'-','-','-'},
    });

    public static readonly IEnumerable<AsciiNumber> All = new[] { Number1, Number3 };
}

假设您的源文件中的数字具有永久和相等的高度,您可以尝试这样的代码:

        string[] lines = File.ReadAllLines("SourceFile.txt");
        var lineHeight = 4;

        var text = new StringBuilder();
        for (var i = 0; i < lines.Length; i += lineHeight)
        {
            var j = 0;
            while (j < lines[i].Length)
            {
                var match = Alphabet.All.FirstOrDefault(character => character.Match(lines, i, j));
                if (match != null)
                {
                    text.Append(match.Character);
                    j += match.Width;
                }
                else
                {
                    j++;
                }
            }
        }
        Console.WriteLine("Recognized numbers: {0}", text.ToString());

注意如果文件的行高发生变化,您必须改进上面的代码。

【讨论】:

  • 您在字母表中添加了其他数字吗?数字的固定高度是否为 4?你明白我的代码是做什么的吗?尽管它与我的测试输入完美配合,但它可能会因您的输入而失败。使用调试器了解问题所在。
【解决方案2】:

假设我们有这个文本,我们想要解析其中的数字:

---       ---      |    |  |     -----   
 /         _|      |    |__|     |___    
 \        |        |       |         |   
--        ---      |       |     ____|

首先,我们应该删除所有不必要的空格(或制表符,如果存在)并在数字之间放置一个分隔符(例如$),得到类似这样的东西:

$---$---$|$|  |$-----$
$ / $ _|$|$|__|$|___ $
$ \ $|  $|$   |$    |$
$-- $---$|$   |$____|$

现在我们应该在文本的每一行调用Split函数,使用$作为分隔符,然后将结果与字母进行比较。

让我们看看如何用代码做到这一点。给定要解析 string[] lines 的文本,我们将创建一个扩展方法来删除不必要的空格并放置一个 separator 字符/字符串:

public static class StringHelperClass
{
    // Extension method to remove any unnecessary white-space and put a separator char instead.
    public static string[] ReplaceSpacesWithSeparator(this string[] text, string separator)
    {
        // Create an array of StringBuilder, one for every line in the text.
        StringBuilder[] stringBuilders = new StringBuilder[text.Length];

        // Initialize stringBuilders.
        for (int n = 0; n < text.Length; n++)
            stringBuilders[n] = new StringBuilder().Append(separator);

        // Get shortest line in the text, in order to avoid Out Of Range Exception.
        int shorterstLine = text.Min(line => line.Length);

        // Temporary variables.
        int lastSeparatorIndex = 0;
        bool previousCharWasSpace = false;

        // Start processing the text, char after char.
        for (int n = 0; n < shorterstLine; ++n)
        {
            // Look for white-spaces on the same position on
            // all the lines of the text.
            if (text.All(line => line[n] == ' '))
            {
                // Go to next char if previous char was also a white-space,
                // or if this is the first white-space char of the text.
                if (previousCharWasSpace || n == 0)
                {
                    previousCharWasSpace = true;
                    lastSeparatorIndex = n + 1;
                    continue;
                }
                previousCharWasSpace = true;

                // Append non white-space chars to the StringBuilder
                // of each line, for later use.
                for (int i = lastSeparatorIndex; i < n; ++i)
                {
                    for (int j = 0; j < text.Length; j++)
                        stringBuilders[j].Append(text[j][i]);
                }

                // Append separator char.
                for (int j = 0; j < text.Length; j++)
                    stringBuilders[j].Append(separator);

                lastSeparatorIndex = n + 1;
            }
            else
                previousCharWasSpace = false;
        }

        for (int j = 0; j < text.Length; j++)
            text[j] = stringBuilders[j].ToString();

        // Return formatted text.
        return text;
    }
}

然后,在Main 方法中,我们将使用:

lines = lines.ReplaceSpacesWithSeparator("$");

ASCIINumbersParser parser = new ASCIINumbersParser(lines, "$");

ASCIINumbersParser 是此类:

public class ASCIINumbersParser
{
    // Will store a list of all the possible numbers
    // found in the text.
    public List<string[]> CandidatesList { get; }

    public ASCIINumbersParser(string[] text, string separator)
    {
        CandidatesList = new List<string[]>();

        string[][] candidates = new string[text.Length][];

        for (int n = 0; n < text.Length; ++n)
        {
            // Split each line in the text, using the separator char/string.
            candidates[n] =
                text[n].Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
        }

        // Put the strings in such a way that each CandidateList item
        // contains only one possible number found in the text.
        for (int i = 0; i < candidates[0].Length; ++i)
            CandidatesList.Add(candidates.Select(c => c[i]).ToArray());
    }
}

此时,我们将使用以下类来生成一些数字的 ASCII 艺术表示,并将结果与​​我们的原始字符串(Main)进行比较:

public static class ASCIINumberHelper
{
    // Get an ASCII art representation of a number.
    public static string[] GetASCIIRepresentationForNumber(int number)
    {
        switch (number)
        {
            case 1:
                return new[]
                {
                    "|",
                    "|",
                    "|",
                    "|"
                };
            case 2:
                return new[]
                {
                    "---",
                    " _|",
                    "|  ",
                    "---"
                };
            case 3:
                return new[]
                {
                    "---",
                    " / ",
                   @" \ ",
                    "-- "
                };
            case 4:
                return new[]
                {
                    "|  |",
                    "|__|",
                    "   |",
                    "   |"
                };
            case 5:
                return new[]
                {
                    "-----",
                    "|___ ",
                    "    |",
                    "____|"
                };
            default:
                return null;
        }
    }

    // See if two numbers represented as ASCII art are equal.
    public static bool ASCIIRepresentationMatch(string[] number1, string[] number2)
    {
        // Return false if the any of the two numbers is null
        // or their lenght is different.

        // if (number1 == null || number2 == null)
        //     return false;
        // if (number1.Length != number2.Length)
        //     return false;

        if (number1?.Length != number2?.Length)
            return false;

        try
        {
            for (int n = 0; n < number1.Length; ++n)
            {
                if (number1[n].CompareTo(number2[n]) != 0)
                    return false;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex);
            return false;
        }

        return true;
    }
}

最后,Main 函数将如下所示:

static void Main()
    {
        string ASCIIString = @"
            ---       ---      |    |  |     -----   
             /         _|      |    |__|     |___    
             \        |        |       |         |   
            --        ---      |       |     ____|  ";

        string[] lines =
            ASCIIString.Split(new[] {"\n","\r\n"}, StringSplitOptions.RemoveEmptyEntries);

        lines = lines.ReplaceSpacesWithSeparator("$");

        ASCIINumbersParser parser = new ASCIINumbersParser(lines, "$");

        // Try to find all numbers contained in the ASCII string
        foreach (string[] candidate in parser.CandidatesList)
        {
            for (int i = 1; i < 10; ++i)
            {
                string[] num = ASCIINumberHelper.GetASCIIRepresentationForNumber(i);
                if (ASCIINumberHelper.ASCIIRepresentationMatch(num, candidate))
                    Console.WriteLine("Number {0} was found in the string.", i);
            }
        }
    }

    // Expected output:
    // Number 3 was found in the string.
    // Number 2 was found in the string.
    // Number 1 was found in the string.
    // Number 4 was found in the string.
    // Number 5 was found in the string.

Here你可以找到完整的代码。

【讨论】:

    【解决方案3】:
    1. 我创建了所有模型并将它们保存在字典中。

    2. 我将创建开发目录 C:\temp\Validate C:\temp\Referenz C:\temp\Extract

    3. 在 Dir Reference 中,将为 Dictionary 中的每个模型创建一个文件。

    4. 我阅读了所有的行,并将它们保存在字符串 [] 中。 编码我会亲自从 string [] 到 char [] []。在此操作之后,我们将在 Dir Validate MyEncoding.txt 文件中包含新号码列表。 从上一个列表中,所有“Char.Empty”(\t) 都被转换为 char null '\0'。

    5. 只要我从左到右逐列浏览列表,

    6. 我从列表中提取字符,具体取决于字典中模型的宽度(例如 NumberOne 的宽度为 2,NumberFour 的宽度为 5)。 每个提取都将保存在 Dir Extract 中的一个新文件中 比较列表中的每个字符是否相同。如果它们是有效的,那么提取的模型将保存在 Dir Validated 中的一个文件中,名称为可识别的模型名称, 并且该文件将用记事本打开几秒钟,然后记事本将关闭,并且将重复搜索过程,直到列表结束。 这种方法的解决方案可以在here!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-25
      • 1970-01-01
      • 1970-01-01
      • 2013-06-27
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多