2011-08-29 6 views
12

así que imagina esta cadena:Leer una cadena, caracteres de 3x3 a la vez

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

¿Cuál sería la forma más fácil/más bonito de dividir esta cadena de modo que cada número podría ser manejado por si mismo?

Estoy pensando en algo así como

public string[] SplitIntoNumbers(string input) 

donde el resultado sería como

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

¿Alguna idea?

Editar
Por querer Thous algo más de información - El problema proviene de la BankOCR -kata encima en CodingDojo. Me doy cuenta de que hay múltiples formas de 'solo hacer el trabajo', soluciones, pero sentí que tenía que haber una forma más 'elegante' de resolverlo. Algo parecido a Clojure.

+0

¿Tiene que usar entrada de cadena, o se puede utilizar una matriz de caracteres Nx3, a continuación, se separaron el uno del grupo en una estructura de 3x3 carbón? ¿Cuál es el razonamiento para las cadenas aquí? (En realidad, están destinadas a trabajar con cadenas de una dimensión donde cada char representa un carácter). – ssube

+2

¿cómo es el parámetro (de entrada)? ¿Puedes escribir un ejemplo? – Tigran

+0

Ver también http://en.m.wikipedia.org/wiki/Seven-segment_display –

Respuesta

1

me gustaría utilizar expresiones regulares para construir una lista de coincidencias con un patrón similar a esta

(.{3}) 

esto rompería la entrada en trozos de partidos, 3x1, y dependiendo del número de partidos que tiene determinaría la números. Por ejemplo

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

generaría 27 partidos de segmentos de 3x1, y dado que cada número es de 3 líneas de alta que sólo puede tomar los 27/3 = 9 números separados. Entonces solo tendrías que recorrer las coincidencias de expresiones regulares y combinarlas en la salida que deseas.

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, y supongo que funcionaría, pero estoy realmente tentado de jugar al viejo ['ahora tienes dos problemas'] (http://regex.info/blog/2006-09-15/247)-card en este caso :-) – Vegar

2

Directo al grano:

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 cadena que utilicé fue la siguiente:

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

Obtengo 'IndexOutOfRangeException' - agregue la cadena de entrada que utilizó, a su pregunta. – Zabba

0

Suponiendo que se desea mantener la matriz de cadenas para la entrada, podríamos hacer un bucle muy simple a través de las líneas tirando 3 caracteres a la vez.

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

Se preguntó:

¿Cuál sería la forma más fácil/más bonito de dividir esta cadena de modo que cada número podría ser manejado por si mismo?

... Creo que es posible que se acerca a esto desde un poco demasiado de una perspectiva OO. De lo que estás hablando es realmente una 'fuente' más de lo que es una colección de personajes. Francamente, resumiría la lógica en una sola clase y definiría los datos de los personajes exactamente como lo hizo para esta publicación. Es fácil de ver, editar y mantener.

yo no entiendo de tu post original si su objetivo final se acaba prestando, o si fue el análisis.De todos modos yo no podía parar en sólo números;)

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

El programa precedente emite el siguiente texto:

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

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

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

nopqrstuvwxyz 
0

¿Qué tal un método de extensión:

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

asumiendo a compatible implementation of InSetsOf() se disponible.

uso:

 var result = input.SplitIntoNumbers(); 
Cuestiones relacionadas