如何解析多行字符串中的数字?

时间:2017-04-09 21:13:04

标签: c# string parsing

从C#中解析以下多行字符串中的数字的推荐方法是什么?

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

2 个答案:

答案 0 :(得分:2)

虽然没有给你一个完整的解决方案,但我建议采用以下方法:

将多行字符串转换为二维字符数组char[,] chars或字符串行string[] lines数组。进一步处理会更容易。

数字由4行组成。因此,在4个行块中处理数组。

数字的宽度不同。通过在彼此之上找到4个空格来搜索数字限制,即chars[line, col] == ' ' && chars[line + 1 , col] == ' ' && chars[line + 2 , col] == ' ' && chars[line + 3 , col] == ' '

然后将数字矩形与已知数字进行比较。也许更简单的是将数字矩形的所有字符组合成一个单行字符串进行比较。数字“3”如下所示:"--- / \ -- "

答案 1 :(得分:1)

Image recognition may be easier... Anyways, here's how you can do it using string parsing:

using System;
using System.Collections.Generic;
using System.Linq;

namespace StackOverflow_DigitRecognition
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = @"
---   ---    |  |   |   -----
 /     _|    |  |___|   |___ 
 \    |      |      |       |
--    ---    |      |   ____|
|  |   |   -----
|  |___|   |___ 
|      |       |
|      |   ____|".TrimStart('\n', '\r');

            var rawDigits = ParseRawInputForDigits(input);
            foreach(string rawDigit in rawDigits)
            {
                int digit = ParseDigit(rawDigit);
                Console.WriteLine(digit);
            }
            Console.ReadKey();
        }

        private static List<string> ParseRawInputForDigits(string input)
        {
            var lines = input.Split('\n');
            const int lineHeight = 4;
            var rawDigits = new List<string>();
            for (int i=0; i < lines.Count(); i+=lineHeight)
            {
                var currentLines = lines.Skip(i).Take(lineHeight).ToList();
                var currentRawDigits = ParseLineForDigits(currentLines);
                rawDigits = rawDigits.Concat(currentRawDigits).ToList();
            }
            return rawDigits;
        }

        private static List<string> ParseLineForDigits(List<string> currentLines)
        {
            // standardize
            currentLines = currentLines.Select(l => l.TrimEnd('\r')).ToList();
            // get columns as strings
            char[,] matrix = MatrixOps.To2D(currentLines.Select(l => l.ToCharArray()).ToArray());
            matrix = MatrixOps.Transpose(matrix);
            var columnsToString = MatrixOps.ColumnsToString(matrix);
            // eliminate extra empty columns
            var filteredColumns = new List<string>();
            foreach(string column in columnsToString)
            {
                if (filteredColumns.Count == 0 || column != "    " || filteredColumns.Last() != "    ") // ' ' * lineHeight
                {
                    filteredColumns.Add(column);
                }
            }
            // separate digits
            var digitColumns = filteredColumns.Split("    ");
            var digits = new List<string>();
            foreach (var digitColumnSet in digitColumns)
            {
                matrix = MatrixOps.To2D(digitColumnSet.Select(l => l.ToCharArray()).ToArray());
                matrix = MatrixOps.Transpose(matrix);
                var rows = MatrixOps.ColumnsToString(matrix);
                string digit = string.Join("\r\n", rows);
                digits.Add(digit);
            }

            return digits;
        }

        private static int ParseDigit(string input)
        {
            var digitFromPattern = new Dictionary<string, int>
            {
                {   @"
|
|
|
|".TrimStart('\n', '\r')
                    , 1
                }
                ,{   @"
---
 _|
|  
---".TrimStart('\n', '\r')
                    , 2
                }
                ,{   @"
---
 / 
 \ 
-- ".TrimStart('\n', '\r')
                    , 3
                }
                ,{   @"
|   |
|___|
    |
    |".TrimStart('\n', '\r')
                    , 4
                }
                ,{   @"
-----
|___ 
    |
____|".TrimStart('\n', '\r')
                    , 5
                }
            };
            return digitFromPattern[input];
        }
    }

    public static class MatrixOps
    {
        public static char[,] Transpose(char[,] matrix)
        {
            int w = matrix.GetLength(0);
            int h = matrix.GetLength(1);

            var result = new char[h, w];

            for (int i = 0; i < w; i++)
            {
                for (int j = 0; j < h; j++)
                {
                    result[j, i] = matrix[i, j];
                }
            }

            return result;
        }

        public static T[,] To2D<T>(T[][] source)
        {
            try
            {
                int FirstDim = source.Length;
                int SecondDim = source.GroupBy(row => row.Length).Single().Key; // throws InvalidOperationException if source is not rectangular

                var result = new T[FirstDim, SecondDim];
                for (int i = 0; i < FirstDim; ++i)
                    for (int j = 0; j < SecondDim; ++j)
                        result[i, j] = source[i][j];

                return result;
            }
            catch (InvalidOperationException)
            {
                throw new InvalidOperationException("The given jagged array is not rectangular.");
            }
        }

        public static List<string> ColumnsToString(char[,] matrix)
        {
            var columnsToString = new List<string>();
            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                columnsToString.Insert(i, "");
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    string column = columnsToString[i];
                    string element = matrix[i, j] + "";
                    column += element;
                    columnsToString[i] = column;
                }
            }
            return columnsToString;
        }
    }

    public static class Extensions
    {
        public static IEnumerable<IEnumerable<TSource>> Split<TSource>(this IEnumerable<TSource> source, TSource splitOn, IEqualityComparer<TSource> comparer = null)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            return SplitIterator(source, splitOn, comparer);
        }

        private static IEnumerable<IEnumerable<TSource>> SplitIterator<TSource>(this IEnumerable<TSource> source, TSource splitOn, IEqualityComparer<TSource> comparer)
        {
            comparer = comparer ?? EqualityComparer<TSource>.Default;
            var current = new List<TSource>();
            foreach (var item in source)
            {
                if (comparer.Equals(item, splitOn))
                {
                    if (current.Count > 0)
                    {
                        yield return current;
                        current = new List<TSource>();
                    }
                }
                else
                {
                    current.Add(item);
                }
            }

            if (current.Count > 0)
                yield return current;
        }
    }
}