将字符转换为ASCII码不起作用。

3

我正在制作一个将字符转换为ASCII码的程序。

用户将输入字符,然后这些字符将被存储到一个数组中,并且程序将把这些字符转换为它们的ASCII值。

下面是我的代码:

package chartoascii;

import java.io.DataInputStream;
import java.io.IOException;

public class CharToAscii {

    public static void main(String[] args) throws IOException 
    {
        DataInputStream in=new DataInputStream(System.in);
        int n;
        Scanner scan = new Scanner(System.in);
        System.out.println("Enter number of Characters you want to insert : ");
        n = scan.nextInt();
        char character[] = new char[n];
        System.out.println("Enter Characters : ");
        for (int i=0; i<n; i++)
        {
            character[i] = in.readChar() ;
        } // for loop

        for (int i=0; i<character.length; i++)
        {
           int ascii = (int) character[i];
           System.out.println(ascii);
        }
    }

}

我的程序运行良好,但我得到的输出不是ASCII代码。

这是我的输出:

Enter number of Characters you want to insert : 
4
Enter Characters : 
a
b
c
d
24842
25098
25354
25610

1
当将 char 强制转换为 int 时,您会得到 Unicode。请注意,Unicode 包括 ASCII,因此像 (int) 'a' 这样的代码会正确地给出 97(ASCII 中的 a)。检查您要转换的内容,将 System.out.println(character[i]); 添加到您的循环中。 - Zabuzard
DataInputStream.readChar()的javadoc说了什么?https://docs.oracle.com/javase/8/docs/api/java/io/DataInputStream.html#readChar--。使用Scanner.nextLine(),并取字符串的第一个字符。 - JB Nizet
1
@Zabuza:更准确地说,你会得到UTF-16编码(除了代理对可能被隔离)。 - T.J. Crowder
正如@JBNizet所说,DataInputStream总是读取两个字节,但Unicode的长度是可变的。特别是像ASCII值这样的小值只由一个字节表示。 - Zabuzard
@Zabuza:不,Unicode 不是可变长度的。有些 转换格式 是(UTF-8、UTF-16), 其他一些则不是(UTF-32)。更多信息请参见:http://www.unicode.org/faq/utf_bom.html。 - T.J. Crowder
谢谢@JBNizet,你是对的,使用scan.next()可以解决问题。 - Atif Ali
3个回答

1
在这一行之后:
n = scan.nextInt();

添加一行代码:
scan.nextLine()

然后,在您的第一个for循环中,使用。
character[i] = scan.nextLine().charAt(0);

每次Scanner将获取您输入的第一个字符,因此稍后强制转换为int将返回其ASCII值。像评论中所说,DataStream是这里的问题。

当然,如果用户调皮,在按回车键之前没有输入任何内容,这将导致错误。 :-) - T.J. Crowder
确实。也许可以用while循环来包围它,并不断检查输入的字符串是否为"",直到最终不是为止,然后将charAt(0)分配给character[i]。或者用try-catch包围它。 - siralexsir88

1

解释

您的代码存在两个问题。更大的问题是DataInputStream不会像您想象的那样读取,另一个问题是您将两个资源连接到System.in,即DataInputStreamScanner。您应该只使用Scanner来读取所有数据。

连接两者的问题在于DataInputStream也会解释先前输入的4,因为它仅由Scanner消耗,但不由DataInputStream消耗。也就是说,我无法复制您的确切值。如果我输入4,然后是abc,那么我将无法输入d,因为DataInputStream也读取了4(我认为原因是您的计算机使用\n作为换行符,而我的计算机使用\r\n)。所以最终的输入是

4
a
b
c

如果我调整您的循环,使其还显示打印出来的内容(作为字符):

for (int i = 0; i < character.length; i++) {
    int ascii = (int) character[i];
    System.out.println(character[i] + " -> " + ascii);
}

我得到了这个:
? -> 24845
? -> 2658
? -> 3338
? -> 25357

好的,那么为什么要使用?代替正确的输入?因此我们需要看一下DataInputStream#readChar的工作原理。根据其文档

返回:此输入流的下两个字节,解释为字符。

然而,为了获得ASCII值,我们需要以类似ASCII的字节流进行解释。 ASCII也有固定的长度,但每个字符只有一个字节而不是两个字节。 但是,如果您还想读取不同的字符,例如äé或甚至,则需要使用某些编码方案(如UTF-16)而不是固定长度来解释字节流。现在请注意,UTF-16不是固定长度的

为了理解这些值,让我们看一下确切的字节流:

01100001 00001101 // ? -> 24845
00001010 01100010 // ? -> 2658
00001101 00001010 // ? -> 3338
01100011 00001101 // ? -> 25357

正如您所看到的,如果我们像这样排列字节(总是两个字节),我们就可以得到相应的十进制格式值。对于ASCII码,我们需要重新排列字节并以此方式读取:

01100001  //  a -> 97
00001101  // \r -> 13
00001010  // \n -> 10
01100010  //  b -> 98
00001101  // \r -> 13
00001010  // \n -> 10
01100011  //  c -> 99
00001101  // \r -> 13

正如您所看到的,字节流中包含的字符不仅仅是 abc,还有 \r\n。这两个字符被解释为换行符命令,因此请参见维基百科

解决方案

最简单的解决方法是使用Scanner及其next方法(文档)。此方法会自动阻塞,直到输入下一个完整的令牌。这是由分隔符模式确定的。为了设置一个UTF-16字符,我们只需用空的String作为分隔符(因此请参考从Scanner获取char输入):

Scanner scanner = new Scanner(System.in);
scanner.useDelimiter("");

之后你可以读取4个String值。然而我们仍然面临\r\n被输入到Scanner的问题。

消除这个问题最简单的方法是使用Scanner#nextLine (文档)。因此,我们不仅仅读取一个字符,而是读取整行。该方法会自动为我们舍弃\r\n

Scanner scanner = new Scanner(System.in);

System.out.println("Enter number of Characters you want to insert : ");
int n = Integer.parseInt(scanner.nextLine());

char[] character = new char[n];
System.out.println("Enter Characters : ");
for (int i = 0; i < n; i++) {
    // Only use first character of line
    character[i] = scanner.nextLine().charAt(0);
}

for (int i = 0; i < character.length; i++) {
    int ascii = (int) character[i];
    System.out.println(character[i] + " -> " + ascii);
}

现在已经正确地打印了ASCII值

a -> 97
b -> 98
c -> 99
d -> 100

准确地说,它打印出UTF-16值,但ASCII包含在UTF-16中。

0
你在每个字母后面输入了另一个字符:换行符(U000a)。这个与上述错误一起,readChar误导性地没有按其名称所声称的那样执行操作,给出了你收到的值:25098是十六进制x620a,x66表示b,x0a表示换行符。通过使用readLine,你可以摆脱换行符。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接