我和一个朋友正在用java编写我们自己的控制台,但是由于unicode字符的宽度无法准确确定,我们在正确调整行时遇到了问题。这就导致了这样的问题:不仅unicode的行,而且下面的行都被移位了。
有办法确定独角兽的宽度吗?
问题的截图可以在下面找到。
它应该是这样的:https://abload.de/img/richtigslkmg.jpeg
这是终端中的一个例子:https://abload.de/img/terminal7dj5o.jpeg
这是PowerShell:https://abload.de/img/powershelln7je0.jpeg中的一个例子
这是Visual代码中的一个示例:https://abload.de/img/visualstudiocode4xkuo.jpeg
这是Putty中的一个例子:https://abload.de/img/putty0ujsk.png
编辑:
很抱歉,这个问题不清楚。
这是关于显示宽度,在示例中,我试图确定显示长度,使每一行具有相同的长度。函数real_length是计算/确定和返回显示宽度。
下面是示例代码:
public static void main(String[] args) {
String[] tests = {
"Peter",
"SHGAMI",
"Marcel №1",
"",
"❤️",
"❤️",
""
};
for(String test : tests) test(test);
}
public static void test(String text) {
int max = 20;
for(int i = 0; i < max;i++) System.out.print("#");
System.out.println();
System.out.print(text);
int length = real_length(text);
for(int i = 0; i < max - length;i++) System.out.print("#");
System.out.println();
}
public static int real_length(String text) {
return text.length();
}发布于 2022-02-22 22:49:24
tl;dr
使用代码点而不是char。避免调用String#length。
input
+
"#".repeat( targetLength - input.codePoints().toArray().length ) 详细信息
你的问题没有显示任何密码。所以我只能猜出你在做什么,问题是什么。
避免char
我猜您的目标是在需要时追加一定数量的数字符号字符,以生成固定长度的文本行。
我猜问题在于您使用的是遗留的char类型,或者它的包装类Character。从Java2开始,char类型基本上就被打破了。作为一个16位的值,char在物理上无法表示大多数字符。
使用代码点号
相反,在处理单个字符时使用码点整数。代码点是永久分配给14万多个在Unicode中定义的字符中的每一个的数字。
Java 5+中的各种代码点相关方法被添加到不同的类中:String、StringBuilder、Character等。
在这里,我们使用String#codePoints获取代码点的IntStream,这是源中每个字符的一个元素。并且我们使用StringBuilder#appendCodePoint为我们的最终结果字符串收集代码点。
final int targetLength = 10;
final int fillerCodePoint = "#".codePointAt( 0 ); // Annoying zero-based index counting.
String input = "";
int[] codePoints = input.codePoints().toArray();
StringBuilder stringBuilder = new StringBuilder();
for ( int index = 0 ; index < targetLength ; index++ )
{
if ( index < codePoints.length )
{
stringBuilder.appendCodePoint( codePoints[ index ] );
} else
{
stringBuilder.appendCodePoint( fillerCodePoint );
}
}或者,使用一个for来缩短这个三元算子循环。
for ( int index = 0 ; index < targetLength ; index++ )
{
int codePoint = ( index < codePoints.length ) ? codePoints[ index ] : fillerCodePoint;
stringBuilder.appendCodePoint( codePoint );
}报告结果。
System.out.println( Arrays.toString( codePoints ) );
String output = stringBuilder.toString();
System.out.println( "output = " + output );128567,129312,129313 输出= #######
可能有一种聪明的方法可以更简单地使用流和lambda编写代码,但我现在想不出其中的一个。
而且,我们可以巧妙地在Java11+中使用String#repeat方法。
String output = input + "#".repeat( targetLength - input.codePoints().toArray().length ) ;发布于 2022-02-25 20:48:26
不幸的是,对于你看似简单的问题,没有简单的解决办法,原因有几点:
System.out只是一个不知道或不关心字体和字符宽度的PrintStream,所以任何解决方案都必须独立于此。println()正在写入的控制台上使用单间距字体,但是这种方法仍然存在一些主要问题。首先,您需要确定一个字体是单间距的,但也将支持您想要呈现的所有字符。当包含表情符号时,这可能会有问题。第二,即使您识别了这样的字体,您可能会发现,该字体的所有符号都不是单间距的!这样的字体将确保(比方说)小写i和大写W具有相同的宽度,但您也不能对表情符号进行这种假设,甚至不能假设“单频”表情符号都具有相同的非标准宽度!第三,您标识的字体(如果存在的话)必须在目标环境(您的PowerShell、朋友的PuTTY外壳等)中可用。这不是一个主要的障碍,但这是另一件值得担心的事情。在所有这些情况下,更好的方法可能是使用Swing或JavaFX,在这里您可以更好地控制正在呈现的输出。即使您不熟悉这些技术,也不需要太长时间就可以工作,只需调整一些通过搜索获得的示例代码即可。即使考虑到学习曲线,也比想出一个健壮的解决方案来对写到任意控制台的任意字符要花费更少的时间,因为这是一个很难解决的问题。
备注:
real_length()方法只是返回所提供的String中的代码点数。它与其内部表示形式有关,并且与呈现字符的宽度没有直接相关性,而呈现字符的宽度由所使用的字体决定。发布于 2022-02-26 02:29:26
注意:这个答案与我以前的回答不同,在质量上也不同(我仍然支持这个答案)。
Java应用程序(即不使用图形用户界面的应用程序)有一种简单的方法来获得在给定字体大小的给定字体中呈现的字符串的宽度。它需要使用一些awt类,即使在非AWT环境中也支持这些类。下面是一个使用问题中提供的数据的演示:
package fixedwidth;
import java.awt.Canvas;
import java.awt.Font;
import java.awt.FontMetrics;
public class FixedWidth {
static String[] tests = {
"Peter", "SHGAMI", "Marcel №1", "", "❤️", "❤️", ""
};
static Font smallFont = new Font("Monospaced", Font.PLAIN, 10);
static Font bigFont = new Font("Monospaced", Font.BOLD, 24);
/**
* This code is based on an answer by SO user Lonzak.
* See SO Answer https://stackoverflow.com/a/18123024/2985643
*/
public static void main(String[] args) {
FontMetrics fm1 = new Canvas().getFontMetrics(FixedWidth.smallFont);
FixedWidth.demo(tests, fm1);
FontMetrics fm2 = new Canvas().getFontMetrics(FixedWidth.bigFont);
FixedWidth.demo(tests, fm2);
}
static void demo(String[] tests, FontMetrics fm) {
Font f = fm.getFont();
System.out.println("\nFont name:" + f.getName() + ", font size:" +
f.getSize() + ", font style:" + f.getStyle());
for (String test : tests) {
int width = fm.stringWidth(test);
System.out.println("width=" + width + ", data=" + test);
}
}
}上面的代码是基于这是Lonzak用户的旧答案的问题没有图形的Java - FontMetrics。这些AWT类允许您创建一个具有定义特征(即名称、大小、样式)的Font,然后在使用该字体时使用FontMetrics实例获取任意字符串的宽度。
下面是运行上面所示代码的输出:
Font name:Monospaced, font size:10, font style:0
width=30, data=Peter
width=60, data=SHGAMI
width=59, data=Marcel №1
width=10, data=
width=30, data=❤️
width=40, data=❤️
width=30, data=
Font name:Monospaced, font size:24, font style:1
width=70, data=Peter
width=149, data=SHGAMI
width=140, data=Marcel №1
width=25, data=
width=73, data=❤️
width=98, data=❤️
width=74, data=备注:

https://stackoverflow.com/questions/71228251
复制相似问题