2011-08-29 81 views
12

Hãy tưởng tượng chuỗi này:Đọc một chuỗi, ký tự 3x3 tại một thời điểm

_ _  _ _ _ _ _ 
    | _| _||_||_ |_ ||_||_| 
    ||_ _| | _||_| ||_| _| 

Điều gì sẽ là chiều/đẹp nhất đơn giản nhất của tách chuỗi này để mỗi số có thể được xử lý bởi nó tự?

Tôi đang nghĩ đến một cái gì đó giống như

public string[] SplitIntoNumbers(string input) 

hiển thị kết quả sẽ như thế nào

["  | |", " _ _||_ ", " _ _| _|", ...] 

ý tưởng Bất kỳ?

Sửa
Đối Nghìn muốn một số chi tiết thông tin - vấn đề này xuất phát từ BankOCR -kata qua tại CodingDojo. Tôi nhận ra rằng có nhiều cách để 'giải quyết các công việc đã hoàn thành', nhưng tôi cảm thấy rằng phải có một cách 'ưa thích' hơn để giải quyết nó. Một cái gì đó giống như clojure.

+0

Bạn phải sử dụng chuỗi đầu vào, hoặc bạn có thể sử dụng một mảng NX3 của chars, sau đó tách ra từng nhóm trong một cấu trúc 3x3 char? Lý do cho chuỗi ở đây là gì (chúng thực sự có ý nghĩa để làm việc với các chuỗi một chiều trong đó mỗi char đại diện cho một ký tự). – ssube

+2

thông số (đầu vào) là gì? Bạn có thể viết một ví dụ? – Tigran

+0

Xem thêm http://en.m.wikipedia.org/wiki/Seven-segment_display –

Trả lời

1

Tôi sẽ sử dụng regex để xây dựng một danh sách các trận đấu với một mô hình tương tự như sau

(.{3}) 

điều này sẽ phá vỡ các đầu vào vào khối của trận 3x1, và tùy thuộc vào có bao nhiêu trận đấu bạn có thể xác định số. Ví dụ:

_ _  _ _ _ _ _ 
    | _| _||_||_ |_ ||_||_| 
    ||_ _| | _||_| ||_| _| 

sẽ tạo 27 kết quả của 3 phân đoạn và vì mỗi số có 3 dòng cao bạn chỉ có thể lấy 27/3 = 9 số riêng biệt. Sau đó, bạn sẽ chỉ phải lặp qua các trận đấu regex và kết hợp chúng vào đầu ra mà bạn muốn.

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(); 
} 
+0

Quảng cáo và tôi đoán nó sẽ hoạt động, nhưng tôi thực sự muốn chơi cái cũ ['bây giờ bạn có hai vấn đề'] (http://regex.info/blog/2006-09-15/247)-card trên cái này :-) – Vegar

2

Đi thẳng vào vấn đề:

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

(EDIT) Chuỗi Tôi đã từng là thế này:

static string str = 
@" 
    _ _  _ _ _ _ _ 
    | _| _||_||_ |_ ||_||_| 
    ||_ _| | _||_| ||_| _|"; 
+0

Tôi nhận được 'IndexOutOfRangeException' - thêm chuỗi đầu vào bạn đã sử dụng, cho câu hỏi của bạn. – Zabba

0

Giả sử bạn muốn giữ lại các mảng của chuỗi cho đầu vào, chúng tôi có thể lặp lại rất đơn giản thông qua các dòng kéo 3 ký tự tại một thời điểm.

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

Bạn hỏi:

Điều gì sẽ là chiều/đẹp nhất đơn giản nhất của tách chuỗi này để mỗi số có thể được xử lý bởi nó tự?

... Tôi nghĩ bạn có thể tiếp cận vấn đề này từ góc độ quá OO. Những gì bạn nói về thực sự là một 'font' nhiều hơn nó là một bộ sưu tập các ký tự. Tôi sẽ thẳng thắn chỉ quấn logic vào một lớp duy nhất và xác định dữ liệu ký tự chính xác như bạn đã làm cho bài đăng này. Thật dễ dàng để xem, chỉnh sửa và duy trì.

Tôi không hiểu từ bài đăng gốc của bạn nếu mục tiêu cuối cùng của bạn chỉ là hiển thị hoặc nếu mục tiêu đó đang phân tích cú pháp.Dù sao tôi có thể không chỉ dừng lại ở con số chỉ;)

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 = " -_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); 
     } 
    } 

Chương trình preceeding kết quả đầu ra văn bản sau đây:

   _ _  _ _ _ _ _ _ 
_   | _| _||_||_ |_ ||_||_|| | 
    ___  ||_ _| | _||_| ||_| _||_| 

-_ 1234567890 
_  _  _ _ _  _ _ 
|_||_ | _||_ |_ | |_| | ||/ | |\| 
| ||_||_ |_||_ | |_-| | | _||\ |_ ||| 

abcdefghijklm 
     _ _ _ _ ___    __ 
|\| _ |_||_||_|/_ | | || |||| \/ \//
| ||_|| ||\ _/ | |_||/ |/| /\ | /_ 

nopqrstuvwxyz 
0

Làm thế nào về một phương pháp khuyến nông:

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

giả a compatible implementation of InSetsOf() được có sẵn.

sử dụng:

 var result = input.SplitIntoNumbers(); 
Các vấn đề liên quan