7

I am trying to print some information in a column-oriented way. Everything works well for Latin characters, but when Chinese characters are printed, the columns stop being aligned. Let's consider an example:

var latinPresentation1 = "some text".PadRight(30) + "| " + 23;
var latinPresentation2 = "some longer text".PadRight(30) + "| " + 23;

Console.WriteLine(latinPresentation1);
Console.WriteLine(latinPresentation2);

Console.WriteLine("..............................................");

var chinesePresentation1 = "一些文字".PadRight(30) + " | " + 23;
var chinesePresentation2 = "一些較長的文字".PadRight(30) + "| " + 23;

Console.WriteLine(chinesePresentation1);
Console.WriteLine(chinesePresentation2);

Output:

some text                     | 23
some longer text              | 23
.................................................
一些文字                           | 23
一些較長的文字                       | 23

As one can see, the Chinese is not aligned to columns. Important note: this is just a presentation of the problem; it won't be used in a console app. Can anyone help me with this?

Boann
  • 48,794
  • 16
  • 117
  • 146
artsch
  • 225
  • 2
  • 10
  • Those chineses chars have a width of 2. If one could find out, for what chars exactly this is true, you could write a custom PadRight-Method that takes that into account, if no better solution comes up. – CSharpie Jan 16 '19 at 11:55
  • @CSharpie - I made some test about that, and looks like chinese characters are not normalized. One cant assume that 1 chinese char = 2 latin char. – artsch Jan 16 '19 at 12:54
  • thats why i said you need to find out, for which chars this is true – CSharpie Jan 16 '19 at 13:04
  • @artsch how will the text be used? Console support on Windows was very bad until the *latest* Windows 10 insider releases. Until recently you'd have to explicitly configure a console window to display Unicode. Test your code in the presentation stack you intend to use, (ASP.NET, WPF, Winforms) and use *their* features to align text. Chances are you won't encounter problems – Panagiotis Kanavos Jan 16 '19 at 13:17
  • @artsch Check [Windows Command-Line: Unicode and UTF-8 Output Text Buffer](https://blogs.msdn.microsoft.com/commandline/2018/11/15/windows-command-line-unicode-and-utf-8-output-text-buffer/) to see why the Console is a mess and what's being done to fix this. The article was posted on November 2018 – Panagiotis Kanavos Jan 16 '19 at 13:20
  • @PanagiotisKanavos - it will be sent as plain text to printer. But not to standard one, it will be receipt printer. – artsch Jan 16 '19 at 13:32
  • @artsch that's bad. In this case you *do* have to deal with the limitations - there's no other presentation layer. The size of each glyph depends on the font used. `PadRight` knows nothing about fonts though, only characters. The size of each glyph will depend on the *printer's* fonts. `MeasureText` can help if you can find the same or equivalent font on Windows. – Panagiotis Kanavos Jan 16 '19 at 13:38
  • @artsch on the other hand, what's missing on Windows Console are the escape commands used to layout text. POS printers typically support the [ESC/POS](https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=72) commands and one of them is used [to set horizontal tab positions](https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=53), just like Word. Instead of padding, you could set the tab positions once and then use tabs in each text line to ensure text appears where you want it to – Panagiotis Kanavos Jan 16 '19 at 13:43

3 Answers3

3

You can use the TextRenderer.MeasureText method from System.Windows.Forms assembly to build the output text basing on string width, instead of characters count.

Here's the util method:

public static string FillWithSpaces(this string text, int width, Font font)
{
    while (TextRenderer.MeasureText(text, font).Width < width)
    {
        text += ' ';
    }
    return text;
}

And the usage:

var font = new Font("Courier New", 10.0F);
var padding = 340;

var latinPresentation1 = "some text ".FillWithSpaces(padding, font) + "| 23";
var latinPresentation2 = "some longer text".FillWithSpaces(padding, font) + "| 23";

var chinesePresentation1 = "一些文字".FillWithSpaces(padding, font) + "| 23";
var chinesePresentation2 = "一些較長的文字".FillWithSpaces(padding, font) + "| 23";

var result = latinPresentation1 + Environment.NewLine +
             latinPresentation2 + Environment.NewLine +
             ".............................................." + Environment.NewLine +
             chinesePresentation1 + Environment.NewLine +
             chinesePresentation2; 

The solution requires padding parameter (in px) and font used.

  • Its not ideal, but looks like ideal solution for this case does not exist. It will do, thanks. – artsch Jan 16 '19 at 14:26
0

I can imagine only one generic solution with padding. You have to use monospace font and all symbols of both alphabets must be the same size. Actually PaddingRight function just adds provided amount of symbols to the string. But displayed size of string also depends on font. In case you use monospace font it will work, in other cases, even for latin symbols it will not. In my opinion, it's better to solve the problem for each particular output which you are going to use, because string itsefl knows nothing about how it will be rendered and more than that it should not aware about it.

Igor
  • 198
  • 1
  • 11
-1

I tried the below code, as I don't have Chinese support I cannot able to test it.

var latinPresentation1 = "some text" ;
var latinPresentation2 = "some longer text";

Console.WriteLine(String.Format("{0,-30} {1,-10} ", latinPresentation1, "| " + 23));
Console.WriteLine(String.Format("{0,-30} {1,-10} ", latinPresentation2, "| " + 23));

Console.WriteLine("..............................................");

var chinesePresentation1 = "一些文字";
var chinesePresentation2 = "一些較長的文字";

Console.WriteLine(String.Format("{0,-30} {1,-10} ", chinesePresentation1, "| " + 23));
Console.WriteLine(String.Format("{0,-30} {1,-10} ", chinesePresentation2, "| " + 23));
Presto
  • 888
  • 12
  • 30
A. Gopal Reddy
  • 370
  • 1
  • 3
  • 16
  • 1
    It doesnt work - > It is basically the same code. All you did was using string.Format instead, which does the same under the hood. – CSharpie Jan 16 '19 at 11:54