Подстрока внутри для цикла, извлекающего больше символов, чем должно - PullRequest
0 голосов
/ 29 августа 2018

Вот проблема, я пытаюсь отобразить текст в полях, поэтому я написал этот код:

string Lines = " If our road signs    Catch your eye          Smile        But don't forget        To buy          Burma Shave    ";
string Sign1 = "┎───────────────────┒\n";
string Sign2 = "│";
string Sign3 = "\n└───────────────────┘";

int highInt;
int lowInt;

for (int i = 0; i < 94; i++)
{
    lowInt = i * 19;
    highInt = lowInt + 19;
    string tempLine = Lines.Substring(lowInt, highInt);

    Console.Write(Sign1);
    Console.Write(Sign2);
    Console.Write(tempLine);
    Console.Write(Sign2);
    Console.Write(Sign3);

    ReadLine();

    tempLine = "";
}
Console.ReadLine();

Но вместо вывода

┎───────────────────┒
│ If our road signs │
└───────────────────┘
┎───────────────────┒
│  catch your eye   │
└───────────────────┘
┎───────────────────┒
│       smile       │
└───────────────────┘

Это выводит:

┎───────────────────┒
│ If our road signs │
└───────────────────┘
┎───────────────────┒
│   catch your eye          Smile      │
└───────────────────┘
┎───────────────────┒
│        Smile        But don't forget        To buy      │
└───────────────────┘

Похоже, он набирает экспоненциально больше символов: 19, затем 38, затем 57, и я не уверен, почему. Я новичок в C #, поэтому извините, если ответ очевиден.

Ответы [ 5 ]

0 голосов
/ 30 августа 2018

Как уже отмечали другие, вы звоните Substring с неправильными значениями. Требуется начальная позиция и длина (и вы переходите в конечную позицию).

Однако другой способ решения этой проблемы может состоять в том, чтобы написать метод, который генерирует для вас знак с определенным текстом и определенной шириной, и затем вы можете просто вызывать этот метод столько раз, сколько захотите, чтобы создать равный знаки.

Если мы напишем метод, который принимает строку и ширину, мы можем соответственно сгенерировать знак. Однако один вопрос, который возникает быстро, заключается в том, что нам делать, если длина строки превышает ширину? Я думаю, что есть два варианта:

  1. Обрезать строку до ширины
  2. Разверните знак, чтобы соответствовать строке

Итак, я добавил параметр expandWidth, который при значении true расширяет знак для размещения самой длинной строки. Если установлено значение false, строка будет обрезана.

Остальная часть метода не требует пояснений: разбить входную строку на символы новой строки, если в знаке должно быть более одной строки, определить самую длинную строку, которую нам нужно отобразить, и настроить ширину знака, если expandWidth is true, запишите нашу строку заголовка (верхняя часть знака), используйте Substring, PadLeft и PadRight, чтобы центрировать каждую строку в ширину, и, наконец, напишите наш нижний колонтитул (нижнюю часть знака ):

public static void  WriteSign(string signText, int signWidth = 10, bool expandWidth = true)
{
    // Split input into lines, in case there's 
    // more than one line to display on the sign
    var lines = signText
        .Split(new[] {'\r', '\n'}, StringSplitOptions.None)
        .Select(line => line.Trim());

    // Determine the sign width based on the longest line
    var actualSignWidth = expandWidth 
        ? Math.Max(lines.Max(l => l.Length), signWidth) 
        : signWidth;

    // Write header
    Console.WriteLine("╔" + new string('═', Math.Max(0, actualSignWidth)) + "╗");

    // Write lines
    foreach (var line in lines)
    {
        var signLine = line.Substring(0, Math.Min(line.Length, actualSignWidth))
        .PadLeft(Math.Min(actualSignWidth, (actualSignWidth + line.Length) / 2))
        .PadRight(actualSignWidth);

        Console.WriteLine("║" + signLine + "║");
    }

    // Write footer
    Console.WriteLine("╚" + new string('═', Math.Max(0, actualSignWidth)) + "╝");
}

Теперь мы можем создать строку с \n символами между каждой группой слов, и мы можем отобразить их все по одному знаку или разделить их и отобразить несколько отдельных знаков.

Например:

private static void Main(string[] cmdArgs)
{
    var signText = "If our road signs\nCatch your eye\nSmile\nBut don't forget\nTo buy\nBurma shave";

    var splitText = signText.Split('\n');
    var signWidth = splitText.Max(line => line.Length) + 2;

    // Write a sign with all the lines on one sign
    WriteSign(signText, signWidth);

    // Write a divider to separate the first sign from the rest
    Console.WriteLine(new string('-', Console.WindowWidth));

    // Write a separate sign for each line
    foreach (var line in splitText) WriteSign(line, signWidth);

    GetKeyFromUser("\nDone! Press any key to exit...");
}

выход

enter image description here

0 голосов
/ 30 августа 2018

Вы можете использовать некоторые интересные возможности C # / .NET, чтобы уменьшить сложность кода. Во-первых, давайте извлечем «форматирование знака» в его собственный статический класс многократного использования, а также добавим ему гибкости:

public static class SignFormatter
{
    private static char SignHorizontalSide = '─';   
    private static char SignTopLeft = '┎'; 
    private static char SignTopRight = '┒';
    private static char SignBottomLeft = '└';
    private static char SignBottomRight = '┘'; 
    private static char SignVerticalSide = '|';

    public static string FormatAsSign(string input, int length)
    {
        //Needed to adjust for end pipes
        length -= 2;

        StringBuilder sb = new StringBuilder();

        //calculates the padding needed to center the string in the sign
        int spaces = length - input.Length;
        int padLeft = spaces / 2 + input.Length;

        //Makes the sign with the centered text
        sb.AppendLine($"{SignTopLeft}{new String(SignHorizontalSide, length)}{SignTopRight}");
        sb.AppendLine($"{SignVerticalSide}{input.PadLeft(padLeft).PadRight(length)}{SignVerticalSide}");
        sb.AppendLine($"{SignBottomLeft}{new String(SignHorizontalSide, length)}{SignBottomRight}");

        return sb.ToString();
    }   
}

Теперь, когда это в своем собственном классе, вы можете использовать Regex для разбиения входной строки на несколько пробелов:

string Lines = " If our road signs    Catch your eye          Smile        But don't forget        To buy          Burma Shave    ";

//splits on multiple spaces, and only takes strings that arent empty
var splitLines = Regex.Split(Lines, @"\s{2,}").Where(s => s != String.Empty);

Затем мы просто перебираем splitLines IEnumerable и применяем наше форматирование знака:

foreach(string s in splitLines)
{
    Console.Write(FormatAsSign(s, 21));
}

На основании вашего ввода и длины знака 21 вы получите такой вывод:

┎───────────────────┒
| If our road signs |
└───────────────────┘
┎───────────────────┒
|  Catch your eye   |
└───────────────────┘
┎───────────────────┒
|       Smile       |
└───────────────────┘
┎───────────────────┒
| But don't forget  |
└───────────────────┘
┎───────────────────┒
|      To buy       |
└───────────────────┘
┎───────────────────┒
|    Burma Shave    |
└───────────────────┘

Я сделал скрипку здесь , чтобы вы могли увидеть это в действии

0 голосов
/ 29 августа 2018

Сначала давайте извлечем метод , который централизует строку:

  private static String ToCenter(String value, int length) {
    if (length <= 0)
      return value;
    else if (string.IsNullOrEmpty(value))
      return new string(' ', length);
    else if (value.Length >= length)
      return value;

    return new string(' ', (length - value.Length) / 2) +
           value +
           new string(' ', (length - value.Length + 1) / 2);
  }

Теперь с помощью Linq давайте обработаем

  string Lines = " If our road signs    Catch your eye          Smile        But don't forget        To buy          Burma Shave    ";

  // Let's get rid of '\n' and have a clear text 
  string Sign1 = "┎───────────────────┒";
  string Sign2 = "│";
  string Sign3 = "└───────────────────┘";

мы можем создать перечислимое число rectangle с (пожалуйста, избегайте использования магических чисел подобно 94, 19, но измените их на Sign1.Length):

  using System.Linq;
  using System.Text.RegularExpressions;
  ...

  var rectangles = Regex
    .Split(Lines, @"\s{2,}")
    .Select(item => item.Trim())
    .Where(item => !string.IsNullOrEmpty(item))
  //.Take(3) // If you want at most 3 rectangles
    .Select(item => string.Join(Environment.NewLine, 
       Sign1, 
       Sign2 + ToCenter(item, Sign1.Length - 2) + Sign2, 
       Sign3));

  foreach (string rectangle in rectangles) {
    // print out the next rectangle
    Console.WriteLine(rectangle);

    //TODO: add all the relevant code here
    // ReadLine();
  }

Единственная хитрая вещь

  Regex.Split(Lines, @"\s{2,}") 

мы разбиваем на два или более пробелов :

 "Smile        But don't forget" -> string[]{" Smile", "But don't forget"}

Итог:

┎───────────────────┒
│ If our road signs │
└───────────────────┘
┎───────────────────┒
│  Catch your eye   │
└───────────────────┘
┎───────────────────┒
│       Smile       │
└───────────────────┘
┎───────────────────┒
│ But don't forget  │
└───────────────────┘
┎───────────────────┒
│      To buy       │
└───────────────────┘
┎───────────────────┒
│    Burma Shave    │
└───────────────────┘

Если вы раскомментируете Take(3), вы получите

┎───────────────────┒
│ If our road signs │
└───────────────────┘
┎───────────────────┒
│  Catch your eye   │
└───────────────────┘
┎───────────────────┒
│       Smile       │
└───────────────────┘
0 голосов
/ 30 августа 2018

Вот решение с различными функциями языка .NET API и C #:

И метод:

public void Boxify()
{
    var lines = " If our road signs    Catch your eye          Smile        But don't forget        To buy          Burma Shave    ";
    var phrases = Regex.Split(lines.Trim(), @"\s{2,}");
    var maxPhraseWidth = phrases.Max(x => x.Length) + 2;

    foreach (var phrase in phrases.Select(Box))
    {
        Console.WriteLine(phrase);
        Console.ReadLine();
    }

    string Box(string phrase)
    {
        var spaceCount = maxTextWidth - phrase.Length;
        var leftSpaceCount = spaceCount / 2;
        var rightSpaceCount = (spaceCount + 1) / 2;

        return $"┎{new string('─', maxTextWidth)}┒\n" +
               $"|{new string(' ', leftSpaceCount)}{phrase}{new string(' ', rightSpaceCount)}|\n" +
               $"└{new string('─', maxTextWidth)}┘";
    }
 }

Поскольку вы новичок в C #, я хочу отметить, что это идиоматическое решение и соответствует общепринятым соглашениям по кодированию для кода C #.

0 голосов
/ 29 августа 2018
Метод подстроки

принимает два параметра. 1-й параметр - начальная позиция. и 2-й является длиной. В вашем случае ваш код должен быть таким.

Вот официальная ссылка.

https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.primitives.stringsegment.substring?view=aspnetcore-2.1

    string Lines = " If our road signs    Catch your eye          Smile        But don't forget        To buy          Burma Shave    ";
    string Sign1 = "┎───────────────────┒\n";
    string Sign2 = "│";
    string Sign3 = "\n└───────────────────┘";

    int length = 19;
    int lowInt;
    for (lowInt = 0; lowInt < Lines.Length ; lowInt+=length )
    {
        var unTraversed = Lines.Length - lowInt;
        if (unTraversed >= length)
        {
            string tempLine = Lines.Substring(lowInt, length);
            Console.Write(Sign1 + Sign2 + tempLine + Sign2 + Sign3);
            Console.ReadLine();
        }
        else
        {
            string tempLine = Lines.Substring(lowInt, Lines.Length - lowInt);
            Console.Write(Sign1 + Sign2 + tempLine + Sign2 + Sign3);
            Console.ReadLine();
        }

    }
    Console.ReadLine();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...