想象一下这个字符串:
_ _ _ _ _ _ _
| _| _||_||_ |_ ||_||_|
||_ _| | _||_| ||_| _|
分割此字符串的最简单/最好的方法是什么,以便每个数字都可以自己处理?
我在考虑像
这样的东西public string[] SplitIntoNumbers(string input)
结果如
[" | |", " _ _||_ ", " _ _| _|", ...]
有什么想法吗?
修改
因为想要更多的信息 - 问题来自BankOCR - kata over CodingDojo。我意识到有多种方法可以“完成工作” - 解决方案,但我觉得必须有一种更''花哨'的解决方法。一些类似于clojure的东西。
答案 0 :(得分:4)
你问:
分割此字符串的最简单/最好的方法是什么,以便每个数字都可以自己处理?
......我认为你可能会从一个OO的角度来看待这个问题。你所说的实际上是一个'字体'而不是一个字符集。我坦率地将逻辑包装成一个单独的类,并完全按照你的帖子定义字符数据。它易于查看,编辑和维护。
如果你的最终目标只是渲染,或者它正在解析,我从原始帖子中无法理解。无论如何,我不能只停留在数字上;)
static void Main()
{
LineBuffers lb = new LineBuffers(80 / 3);
lb.Write(0, "-_ 1234567890");
Console.WriteLine(String.Join(Environment.NewLine, lb.Lines.ToArray()));
Console.WriteLine();
Console.WriteLine(lb.ReadLine());
lb.Clear();
lb.Write(0, "abcdefghijklm");
Console.WriteLine(String.Join(Environment.NewLine, lb.Lines.ToArray()));
Console.WriteLine();
Console.WriteLine(lb.ReadLine());
lb.Clear();
lb.Write(0, "nopqrstuvwxyz");
Console.WriteLine(String.Join(Environment.NewLine, lb.Lines.ToArray()));
Console.WriteLine();
Console.WriteLine(lb.ReadLine());
lb = new LineBuffers(" _ _ _ _ ", "|_| _ | |_ |_|", @"|\ |_||_-|_ |\ ");
Console.WriteLine(lb.ReadLine());
}
public class LineBuffers
{
private static string Characters = " -0123456789_abcdefghijklmnopqrstuvwxyz";
private static readonly string[] Format =
(
@". . . _ . . _ . _ . . _ . _ . _ . _ . _ . . _ . . _ . . _ . _ . _ . . _ . _. . . . . . _ . _ . _ . _ .___. . . . . .__ ." + "\n" +
@". . _ .| |. |. _|. _|.|_|.|_ .|_ . |.|_|.|_|. .|_|.|_ .| . _|.|_ .|_ .| .|_|. | . |.|/ .| .|\|.|\|. _ .|_|.|_|.|_|./_ . | .| |.| |.|||. \/. \/. / ." + "\n" +
@". . .|_|. |.|_ . _|. |. _|.|_|. |.|_|. _|.___.| |.|_|.|_ .|_|.|_ .| .|_-.| |. | . _|.|\ .|_ .|||.| |.|_|.| . |.|\ . _/. | .|_|.|/ .|/|. /\. | ./_ ."
).Split('\n');
private readonly char[][] _lines;
public LineBuffers(int charWidth)
{
_lines = new char[3][] {new char[charWidth*3], new char[charWidth*3], new char[charWidth*3]};
Clear();
}
public LineBuffers(string line1, string line2, string line3)
: this(line1.ToCharArray(), line2.ToCharArray(), line3.ToCharArray()) { }
public LineBuffers(char[] line1, char[] line2, char[] line3)
{
if (line1 == null || line2 == null || line3 == null
|| line1.Length != line2.Length || line2.Length != line3.Length)
throw new ArgumentException();
_lines = new char[3][] {
line1, line2, line3
};
}
public int Count { get { return _lines[0].Length / 3; } }
public IEnumerable<string> Lines { get { return _lines.Select(chars => new String(chars)); } }
public void Clear()
{
for (int i = 0; i < Count; i++)
Write(i, ' ');
}
public void Write(int position, IEnumerable<Char> character)
{ foreach (char ch in character) Write(position++, ch); }
public void Write(int position, Char character)
{
int charIx = Characters.IndexOf(Char.ToLower(character));
if (charIx < 0)
throw new ArgumentOutOfRangeException("character");
if (position >= Count)
throw new ArgumentOutOfRangeException("position");
int offset = charIx*4 + 1;
for(int line=0; line <3; line++)
Array.Copy(Format[line].ToCharArray(offset, 3), 0, _lines[line], position * 3, 3);
}
public Char Read(int position)
{
if (position >= Count)
throw new ArgumentOutOfRangeException("position");
IEnumerable<int> found = Find(Format[0], _lines[0], position*3)
.Intersect(Find(Format[1], _lines[1], position*3))
.Intersect(Find(Format[2], _lines[2], position*3));
int[] result = found.ToArray();
if (result.Length != 1)
throw new FormatException();
return Characters[result[0]];
}
IEnumerable<int> Find(string findIn, char[] text, int charIx)
{
for(int i=1; i < findIn.Length; i += 4)
{
if (findIn[i] == text[charIx] && findIn[i + 1] == text[charIx + 1] && findIn[i + 2] == text[charIx + 2])
yield return i/4;
}
}
public string ReadLine()
{
char[] text = new char[Count];
for (int ix = 0; ix < Count; ix++)
text[ix] = Read(ix);
return new String(text);
}
}
前面的程序输出以下文字:
_ _ _ _ _ _ _ _
_ | _| _||_||_ |_ ||_||_|| |
___ ||_ _| | _||_| ||_| _||_|
-_ 1234567890
_ _ _ _ _ _ _
|_||_ | _||_ |_ | |_| | ||/ | |\|
| ||_||_ |_||_ | |_-| | | _||\ |_ |||
abcdefghijklm
_ _ _ _ ___ __
|\| _ |_||_||_|/_ | | || |||| \/ \/ /
| ||_|| ||\ _/ | |_||/ |/| /\ | /_
nopqrstuvwxyz
答案 1 :(得分:2)
直截了当:
public static string[] SplitIntoNumbers(string input)
{
List<string> result = new List<string>();
string[] subStrs = input.Split(new char[] { '\r', '\n' }, 3, StringSplitOptions.RemoveEmptyEntries);
for (int it = 0; it < subStrs[0].Length; it += 3)
{
result.Add(subStrs[0].Substring(it, 3)
+ subStrs[1].Substring(it, 3)
+ subStrs[2].Substring(it, 3));
}
return result.ToArray();
}
(编辑)我使用的字符串是:
static string str =
@"
_ _ _ _ _ _ _
| _| _||_||_ |_ ||_||_|
||_ _| | _||_| ||_| _|";
答案 2 :(得分:1)
我会使用正则表达式来构建一个匹配列表,其模式与此类似
(.{3})
这会将输入分成3x1匹配的块,并且取决于你有多少匹配将确定数字。例如
_ _ _ _ _ _ _
| _| _||_||_ |_ ||_||_|
||_ _| | _||_| ||_| _|
将产生27个3x1段的匹配,并且因为每个数字是3行高,所以你可以采用27/3 = 9个单独的数字。然后你只需要遍历正则表达式匹配并将它们组合成你想要的输出。
void Main()
{
string input = " _ _ _ _ _ _ _ \r\n | _| _||_||_ |_ ||_||_|\r\n ||_ _| | _||_| ||_| _|";
string[] result = SplitIntoNumbers(input);
}
public string[] SplitIntoNumbers(string input)
{
List<string> results = new List<string>();
Regex rx = new Regex("(.{3})");
MatchCollection matches = rx.Matches(input);
int totalNumbers = matches.Count / 3;
for(int i = 0; i < totalNumbers; i++)
{
string s = string.Concat(matches[i].Value, matches[i + totalNumbers].Value, matches[i + (totalNumbers * 2)].Value);
results.Add(s);
}
return results.ToArray();
}
答案 3 :(得分:0)
假设你想保留输入的字符串数组,我们可以非常简单地循环通过一次拉3个字符的行。
var numbers = new[]
{
" _ _ _ _ _ _ _ ",
" | _| _||_||_ |_ ||_||_|",
" ||_ _| | _||_| ||_| _|"
};
// just in case length is off on one, don't want to crash
var length = numbers.Min(line => line.Length);
var results = new List<string>();
// go by groups of three
for (int i = 0; i < length; i += 3)
{
var builder = new StringBuilder();
for (int j = 0; j < numbers.Length; j++)
{
builder.Append(numbers[j].Substring(i, 3));
}
results.Add(builder.ToString());
}
// print the results
foreach (var digit in results)
{
Console.WriteLine(digit);
}
答案 4 :(得分:0)
扩展方法怎么样:
public static string[] SplitIntoNumbers(this string str)
{
var lines = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
var columns = lines
.Select(x => x.InSetsOf(3).Select(y => new string(y.ToArray())).ToList())
.ToList();
var numbers = Enumerable.Range(0, columns[0].Count)
.Select(x => columns[0][x] + columns[1][x] + columns[2][x])
.ToArray();
return numbers;
}
假设a compatible implementation of InSetsOf()可用。
用法:
var result = input.SplitIntoNumbers();