2011-08-29 12 views
12

Quindi immaginate questa stringa:Leggere una stringa, caratteri 3x3 alla volta

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

Quale sarebbe il modo più semplice/più bella di scissione questa stringa in modo che ogni numero potrebbe essere gestito da esso auto?

Sto pensando a qualcosa di simile

public string[] SplitIntoNumbers(string input) 

in cui il risultato sarebbe come

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

Tutte le idee?

Modifica
Per thous volendo qualche informazione in più - Il problema viene dal BankOCR -kata sopra a CodingDojo. Mi rendo conto che ci sono molti modi per risolvere il problema, ma ho sentito che doveva esserci un modo più "elaborato" di risolverlo. Qualcosa di simile a un clojure.

+0

Dovete utilizzare l'ingresso di stringa, o si può utilizzare una gamma NX3 di caratteri, poi divisi fuori di ogni gruppo in una struttura 3x3 char? Qual è il ragionamento per le stringhe qui (in realtà sono pensate per lavorare con stringhe unidimensionali in cui ogni carattere rappresenta un carattere). – ssube

+2

come è il parametro (input)? Puoi scrivere un esempio? – Tigran

+0

Vedere anche http://en.m.wikipedia.org/wiki/Seven-segment_display –

risposta

1

userei regex per costruire una lista di partite con un modello simile a questo

(.{3}) 

questo avrebbe rotto l'ingresso in blocchi di partite 3x1, e in base alla quantità di partite avete determinerebbe la numeri. Per esempio

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

genererebbe 27 partite di segmenti di 3x1, e dal momento che ogni numero è alto 3 linee si può semplicemente prendere i 27/3 = 9 numeri separati. Quindi dovresti semplicemente scorrere le corrispondenze regolari e combinarle nell'output che desideri.

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

Creativo, e immagino che funzionerebbe, ma sono davvero tentato di suonare il vecchio ['ora hai due problemi'] (http://regex.info/blog/2006-09-15/247)-card su questo :-) – Vegar

2

Dritto al punto:

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) La stringa che ho usato è stato questo:

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

Ottengo 'IndexOutOfRangeException' - aggiungi la stringa di input che hai usato, alla tua domanda. – Zabba

0

Supponendo che si desidera mantenere l'array di stringhe per l'ingresso, potremmo fare un loop molto semplicemente attraverso le linee che tirano 3 caratteri alla volta.

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

ti ha chiesto:

quale sarebbe il modo più semplice/più bella di scissione questa stringa in modo che ogni numero potrebbe essere gestito da esso auto?

... penso che potrebbe essere avvicinando questo da un po 'troppo di una prospettiva OO. Ciò di cui stai parlando è davvero un "font" più che una collezione di personaggi. Vorrei francamente racchiudere la logica in una singola classe e definire i dati del personaggio esattamente come hai fatto per questo post. È facile da vedere, modificare e mantenere.

Non ho capito dal tuo post originale se il tuo obiettivo finale era solo il rendering, o se stava analizzando.In ogni caso non ho potuto solo fermarsi al solo numeri;)

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

Il programma precedente emette il seguente testo:

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

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

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

nopqrstuvwxyz 
0

Che ne dite di un metodo di estensione:

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

assumendo a compatible implementation of InSetsOf() è a disposizione.

utilizzo:

 var result = input.SplitIntoNumbers(); 
Problemi correlati