for循环中的子字符串提取了比应提取的字符更多的字符

时间:2018-08-29 20:26:40

标签: c# string for-loop

这是问题所在,我试图在框中显示文本,所以我写了这段代码:

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 :(得分:2)

您可以利用一些很酷的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    |
└───────────────────┘

我做了一个小提琴here,所以您可以看到它的作用

答案 1 :(得分:0)

substring方法有两个参数。第一个参数是起始位置。第二个是长度就您而言,您的代码应像这样。

这是官方链接。

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

答案 2 :(得分:0)

首先,让我们提取一个将字符串集中的方法

  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的枚举(请避免使用像9419这样的魔术数字,但将其更改为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       │
└───────────────────┘

答案 3 :(得分:0)

以下是具有多种.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#的新手,所以我想指出这是一种idiomatic解决方案,并且遵循C#代码普遍采用的coding conventions

答案 4 :(得分:0)

正如其他人指出的那样,您正在以错误的值调用Substring。它需要一个起始位置和一个长度(并且您要经过终点位置)。

但是,解决此问题的另一种方法可能是编写一个为您生成带有特定文本和特定宽度的符号的方法,然后您可以随意调用该方法多次,以生成相等的符号大小的标志。

如果我们编写一个采用字符串和宽度的方法,则可以相应地生成一个符号。但是,一个很快出现的问题是,如果字符串长于宽度,我们该怎么办?我认为有两种选择:

  1. 截断字符串以适合宽度
  2. 展开符号以适合字符串

因此,我添加了一个expandWidth参数,当设置为true时,它将扩展符号以容纳最长的字符串。如果设置为false,它将截断字符串。

该方法的其余部分很不言自明:如果符号应该多于一行,请在换行符上分割输入字符串,确定我们需要显示的最长行,并调整符号宽度,如果{{1 }}是expandWidth,写出标题字符串(符号的顶部),使用trueSubstringPadLeft将每行的宽度居中,并最后写上我们的页脚(符号的底部):

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

输出

enter image description here