进制,字符简单总结

2022-08-12  本文已影响0人  梧叶已秋声

1.进制

进制是什么?进制不是孤立存在的,了解进制之前需要先了解数制。
记数系统,或称记数法或数制。是使用一组数字符号来表示数的体系。

一个理想的记数系统能够:1.有效地描述一组数(例如,整数、实数)2.所有的数对应唯一的表示(至少有一个标准表示法)3.反映数的代数和算术结构

记数系统可以按照以下方式分类:

按照进位制,可分为十进制、二进制、八进制等。按照写法,可分为中文数字、阿拉伯数字、罗马数字等。

如何记数?这就是靠进位制了。

名称 基数 进位
二进制 0,1 逢2进1
八进制 0,1,2,3,4,5,6,7 逢8进1
十进制 0,1,2,3,4,5,6,7,8,9 逢10进1
十六进制 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f 逢16进1

下面是二进制与八进制转换。
二进制 → 八进制
方法:取三合一法,即从二进制的小数点为分界点,向左(向右)每三位取成一位,接着将这三位二进制按权相加,然后,按顺序进行排列,小数点的位置不变,得到的数字就是我们所求的八进制数。如果向左(向右)取三位后,取到最高(最低)位时候,如果无法凑足三位,可以在小数点最左边(最右边),即整数的最高位(最低位)添0,凑足三位。
例:将二进制的(11010111.0100111)B转换为八进制的步骤如下:

  1. 小数点前111 = 7;
  2. 010 = 2;
  3. 11补全为011,011 = 3;
  4. 小数点后010 = 2;
  5. 011 = 3;
  6. 1补全为100,100 = 4;
  7. 读数,读数从高位到低位,即(11010111.0100111)B=(327.234)O。
    https://www.cnblogs.com/gaizai/p/4233780.html
    八进制 → 二进制
    https://www.cnblogs.com/gaizai/p/4233780.html

方法:取一分三法,即将一位八进制数分解成三位二进制数,用三位二进制按权相加去凑这位八进制数,小数点位置照旧。
例:将八进制的(327)O转换为二进制的步骤如下:

  1. 3 = 011;

  2. 2 = 010;

  3. 7 = 111;

  4. 读数,读数从高位到低位,011010111,即(327)O=(11010111)B。

https://www.cnblogs.com/gaizai/p/4233780.html
更多转换,可参考这个:
二、八、十、十六进制转换(图解篇)

2.字符

计算机中处理的数据有两类:数值数据和非数值数据。数值数据指表示数量的数据,有正负和大小之分,在计算机中以二进制的形式存储和进行运算。非数值数据包括字符、汉字、声音和图像等,在计算机中处理前必须以某种编码形式转换成二进制数表示(例如ASCII表)。

编码是信息从一种形式或格式转换为另一种形式的过程,也称为计算机编程语言的代码简称编码。用预先规定的方法将文字、数字或其它对象编成数码,或将信息、数据转换成规定的电脉冲信号。编码在电子计算机电视、遥控和通讯等方面广泛使用。编码是信息从一种形式或格式转换为另一种形式的过程。解码,是编码的逆过程。

字符,在计算机中处理前必须以某种编码形式转换成二进制数表示。什么是字符?有哪几种常见编码形式?

简单地看下 字符的概念。

字符(character)是一段文字的最小单位,它可能是汉字、阿拉伯数字、英文字母、日语假名、标点符号或其他有意义的内容。

常见编码格式有ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16、Unicode等。

例如ASCII 码表中的字符 * ,计算机要如何识别该数据呢?这就需要解码了。凡是有编码的地方,就需要解码。这里计算机需要对应ASCII码表去解码。 * 对应二进制数值为0010 1010。

image
unicode是字符集,utf-8、utf-16等是表现形式(编码方式,类似于中文跟行书、楷书等的关系)。
Unicode 是 Java 和 XML 的基础。
Unicode译为万国码、国际码。Unicode是为了解决传统的字符编码方案的局限而产生的,例如ISO 8859-1所定义的字符虽然在不同的国家中广泛地使用,可是在不同国家间却经常出现不兼容的情况。

Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符。

Unicode只是一个符号集, 它只规定了符号的二进制代码, 却没有规定这个二进制代码应该如何存储(因此有了utf-8 -16 -32)

比如UTF-8、UTF-16、UTF-32都是Unicode编码的实现方式,不过UTF-8是使用最多的实现

下面的链接是在网上搜到的Unicode编码表:
https://pan.baidu.com/s/1slg2Pit
可以直接通过表查看字符在编码表对应的数据(十六进制)。

Unicode编码表.pdf Unicode编码表.pdf

通过查看不同的编码表可以看出,同一个字符,在不同的编码表中,对应的数据是不同的,例如!,在ASCII 和unicode表中的位置是不同的,数据不一致。

其实还可以直接使用Notepad++的插件查看,下面来直接查看UTF-8 的编码格式对应的数据。

在安装完所需插件(HEX-Editor)后,新建txt文档,写下“如”字。

image

然后使用插件,查看对应的utf-8的十六进制数据。

image

可以自己修改编码格式,然后查看对应的十六进制数据。

字符串是由数字、字母、下划线组成的一串字符。

3.转换函数

3.1 int和String之间的转换

由于数据类型较多,所以这里先通过简单看一个十六进制int数据A5转换成十进制int 数据165来看看那些常用API。

3.1.1 十六进制int转十进制int

//定义一个十六进制数据 A5 ,需要转换成十进制int 165
int hexInt = 0xA5;

首先需要把int转换成String。这里有个要注意的地方,如果直接使用+ ""去转换的话,会把0xA5转为十进制的165。
String test = hexInt + "" 会产生两个String对象,首先会把十六进制的int转换,生成一个存放十进制数据的String,最后得到的数据是"165"这个字符串。如果得到了"165"这个字符串,可以通过Integer.valueOf(test,10),获得Integer数据。 Integer自动拆箱。

int hexInt = 0xA5;
String test =  hexInt + "";
//Integer 自动拆箱
int decInt = Integer.valueOf(test, 10);
Log.d(TAG,"test >> 十进制 int :" +  test  + " >> "
                +  decInt );

打印结果如下


如果想得到"a5"这个字符串,再去转换进制,需要使用
Integer.toString(hexInt,16)Integer.toHexString(hexInt)把十六进制的int数据转化为十六进制的String,再使用 Integer.parseInt(hexString,16)返回一个十进制的int数据(Integer.parseInt(String s,int radix)返回的结果是一个十进制数)
如果需要返回Integer类型,就使用Integer.valueOf。parseInt效率比valueof效率高,valueof就是调用了parseInt方法的,并且多了一个装箱的操作,将int封装为Integer。

int hexInt = 0xA5;
//把十六进制的int 转换成十六进制的String
String hexString = Integer.toString(hexInt,16);
Log.d(TAG,"十六进制 hexString >> 十进制 int :" +  hexString  + " >> "
                +  Integer.parseInt(hexString,16) );

打印结果如下


image.png

如果想得到大写的A5,那么需要调用String中的toUpperCase函数。

    public String toUpperCase() {
        return toUpperCase(Locale.getDefault());
    }

转换的基本流程是:
1.int先转String
2.进制转换
3.String再转回int。

实际上Integer 把1和2合并。
这里Integer.toString其实还可以直接把十六进制的int,转换成十进制的String。如果不需要把string转int的话,这样就可以了。

int hexInt = 0xA5;
//把十六进制的int 转换成十进制的String
String decString = Integer.toString(hexInt,10);
Log.d(TAG,"十进制 decString >> 十进制 int :" +  decString  + " >> "
                +  Integer.parseInt(decString,10) );

打印结果如下


image.png

3.1.2 int转String

int转string,Integer中有如下方法。

image.png
其实String也有函数可以使用,formatvalueOf
image.png
image.png
String.format("%d", hexInt)String.valueOf(int i),返回十进制的String。

十六进制 int数据 >> 十进制String 为例,转十进制String有如下几种方法。

int hexInt = 0xA5;
//转十进制String
Log.d(TAG,"Integer.toString(hexInt,10): " + Integer.toString(hexInt,10)
                 + " Integer.toString(hexInt): " + Integer.toString(hexInt)
                 + "+字符串连接 : " + (hexInt+"")
                 + " String.format: " +  String.format("%d", hexInt)
                 + " String.valueOf(hexInt): "+ String.valueOf(hexInt));

log如下
Integer.toString(hexInt,10): 165 Integer.toString(hexInt): 165+字符串连接 : 165 String.format: 165 String.valueOf(hexInt): 165

十六进制 int数据 >> 十六进制String 为例,转十六进制String方法如下:

int hexInt = 0xA5;
//转十六进制String
Log.d(TAG,"Integer.toString(hexInt,16): " + Integer.toString(hexInt,16)
                + " Integer.toHexString(hexInt): " +  Integer.toHexString(hexInt)
                + " String.format %x: " +  String.format("%x", hexInt));

log如下
Integer.toString(hexInt,16): a5 Integer.toHexString(hexInt): a5 String.format %x: a5

需要转换成其他进制,例如二进制String的话,就把16换成2,toHexString换成toBinaryString。

int hexInt = 0xA5;
//转二进制String
Log.d(TAG,"Integer.toString(hexInt,2): " + Integer.toString(hexInt,2)
                + " Integer.toBinaryString(hexInt): " +  Integer.toBinaryString(hexInt));

Integer.toString(hexInt,2): 10100101 Integer.toBinaryString(hexInt): 10100101

3.1.3 String转int

Integer中有如下方法


image.png
image.png

十六进制String >> 十进制 int数据方法如下:

String hexString = "A5";
//十六进制string 转 十进制int
Log.d(TAG,"Integer.parseInt(hexString,16): " + Integer.parseInt(hexString,16)
                + " Integer.valueOf(hexString,16): " +  Integer.valueOf(hexString,16));

log如下
Integer.parseInt(hexString,16): 165 Integer.valueOf(hexString,16): 165

其他进制,例如十进制String,需要转换成十进制的int数据的话,也是使用parseInt。

String decString = "165";
//十进制string 转 十进制int
Log.d(TAG,"Integer.parseInt(decString,10): " + Integer.parseInt(decString,10)
                + " Integer.valueOf(decString): " +  Integer.valueOf(decString));

log如下
Integer.parseInt(decString,10): 165 Integer.valueOf(decString): 165

这里好像只有转为十进制int的方法。十六进制的string没有转为十六进制int的方法。

最常用的2个函数toStringparseInt
Integer.toString(int,16): int转换成的十六进制的String后返回
Integer.parseInt(string,16)返回从十六进制的string中解析出的int

常用String间进制转换

        Log.d(TAG,"二进制 >> 十六进制: " + Integer.toString(0b111,16)
                + " 十进制 >> 二进制: "   + Integer.toString(12,2)
                + " 十六进 >> 十进制: " + Integer.toString(0x111,10)
                + " 十进制 >> 十六进制: " + Integer.toString(12,16)
        );

log如下
二进制 >> 十六进制: 7 十进制 >> 二进制: 1100 十六进 >> 十进制: 273 十进制 >> 十六进制: c

注意:要是数据太大,就要用BigInteger

4.String与byte[]的转换

1.字节数组转16进制字符串

    /*
     * 字节数组转16进制字符串
     */
    public static String bytes2HexString(byte[] b) {
        String r = "";
        
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            r += hex.toUpperCase();
        }
        
        return r;
    }

   public static String byteToString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            sb.append(String.format("%02X", bytes[i]));
        }
        return sb.toString();
    }

2.16进制字符串转字节数组

    /**
     * 将16进制字符串转换为byte[]
     *
     * @param str
     * @return
     */
    public static byte[] hexToBytes(String str) {
        if(str == null || str.trim().equals("")) {
            return new byte[0];
        }

        byte[] bytes = new byte[str.length() / 2];
        for(int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }

        return bytes;
    }

简单测试一下这函数。

        try {
            byte[] bytes = "测试".getBytes("utf-8");
            String str = "e6b58be8af95";
            Log.d(TAG, "字节数组为: " + Arrays.toString(bytes)
                    + " byteToString = " + byteToString(bytes)
                    + " hexToBytes = " + Arrays.toString(hexToBytes(str))
                    + " byte[] 转 utf-8字符: " + new String(hexToBytes(str), "utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

log如下
字节数组为: [-26, -75, -117, -24, -81, -107] byteToString = E6B58BE8AF95 hexToBytes = [-26, -75, -117, -24, -81, -107] byte[] 转 utf-8字符: 测试

  1. byte转化成2进制字符串
  /**
     * 把byte转化成2进制字符串
     * @param b
     * @return
     */
    public static String getBinaryStrFromByte(byte b){
        String result ="";
        byte a = b; ;
        for (int i = 0; i < 8; i++){
            byte c=a;
            a=(byte)(a>>1);//每移一位如同将10进制数除以2并去掉余数。
            a=(byte)(a<<1);
            if(a==c){
                result="0"+result;
            }else{
                result="1"+result;
            }
            a=(byte)(a>>1);
        }
        return result;
    }
byte aByte = (byte) 0xA5;
Log.d(TAG," byte = " + aByte + "  getBinaryStrFromByte = "+ getBinaryStrFromByte(aByte));

log如下。
byte = -91 getBinaryStrFromByte = 10100101

4.byte[]和string转换还有一个乱码的问题要注意。
乱码问题根源:编码与解码所用的字符编码方式不一致

byte[] b_GBK = "中国".getBytes("GBK");
byte[] b_UTF8 = "中国".getBytes("UTF-8");
byte[] b_ISO88591 = "中国".getBytes("ISO8859-1");

//对字节数组按照指定的字符编码方式解码
System.out.println(new String(b_UTF8, "UTF-8"));
System.out.println(new String(b_UTF8, "ISO8859-1"));
System.out.println(new String(b_ISO88591, "UTF-8"));

运行结果

中国
中国
??

第二行乱码因为:编码UTF-8,解码ISO8859-1,编解码所用的字符编码方式不一致
第三行乱码因为:编码ISO8859-1,解码UTF-8,编解码所用的字符编码方式不一致
只有保持编解码所用的字符编码方式一致就可以避免乱码。

5.String和Ascii的相互转化

java八进制、十进制、十六进制(hex)ASCII码字符串和String互转
在做Android串口开发的时候,与串口设备间的通信经常内容都是16进制的。发送命令的时候需要先把命令转成16进制的ASCII字符串。接收到设备的反馈时需要把16进制的ASCII字符串转成对应的明文。
比如我们要 发送 的明文为ABCDEF,需要先转成对应的16进制ASCII码字符串414243444546,我们 收到 的反馈为16进制的ASCII码字符串313233343536,需要转成对应的明文123456

1.16进制ASCII码和单个字符char的互转

// hex转char
// 先将hex字符串转成int
int i = Integer.parseInt("46", 16);
// hex转char方法一,结果为F
String str1 = new String(new char[]{(char)i});
// hex转char方法二,结果为F
String str2 = new StringBuffer().append((char)i).toString();
 
// char转hex方法一,结果为46(第二个参数16表16进制)
String hex1 = Integer.toString(c, 16);
// char转hex方法二,结果为46
String hex2 = Integer.toHexString('F');

2.ASCII码hex字符串转String明文
每两个字符表示的16进制ASCII码解析成一个明文字符

public static String hex2Str(String hex) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < hex.length() - 1; i += 2) {
        String h = hex.substring(i, (i + 2));
        int decimal = Integer.parseInt(h, 16);
        sb.append((char) decimal);
    }
    return sb.toString();
}
 
// 输出结果为ABCDEF
System.out.println(hex2Str("414243444546"));

3.String明文转ASCII码hex字符串
一个明文字符生成两个字符表示的16进制ASCII码

public static String str2Hex(String str) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < str.length(); i++) {
        char c = str.charAt(i);
        // 这里的第二个参数16表示十六进制
        sb.append(Integer.toString(c, 16));
        // 或用toHexString方法直接转成16进制
        // sb.append(Integer.toHexString(c));
    }
    return sb.toString();
}
 
// 输出结果为414243444546
System.out.println(str2Hex("ABCDEF"));

4.十进制ASCII码字符串和String明文互转
10进制的转换和16进制的类似,只有细微的差别,直接看代码
10进制ASCII转String

public static String dec2Str(String ascii) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < ascii.length() - 1; i += 2) {
        String h = ascii.substring(i, (i + 2));
        // 这里第二个参数传10表10进制
        int decimal = Integer.parseInt(h, 10);
        sb.append((char) decimal);
    }
    return sb.toString();
}
 
// 结果为ABCDEF
System.out.println(dec2Str("656667686970"));

String转10进制ASCII

public static String str2Dec(String str) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < str.length(); i++) {
        char c = str.charAt(i);
        // 第二个参数10表示10进制
        sb.append(Integer.toString(c, 10));
        // 或者省略第二个参数,默认为10进制
        // sb.append(Integer.toString(c));
    }
    return sb.toString();
}
 
// 结果为656667686970
System.out.println(str2Dec("ABCDEF"));

5.八进制ASCII码字符串和String明文互转
八进制ASCII码的转换也类似,主要要注意的地方是八进制的ASCII码占三位,而16进制和十进制表示法只占两位

8进制ASCII转String

public static String oct2Str(String ascii) {
    StringBuilder sb = new StringBuilder();
    // 这里这里循环的步进为3,因为8进制的ASCII码占3位
    for (int i = 0; i < ascii.length() - 2; i += 3) {
        String h = ascii.substring(i, (i + 3));
        // 第二个参数8表8进制
        int decimal = Integer.parseInt(h, 8);
        sb.append((char) decimal);
    }
    return sb.toString();
}
 
// 结果为ABCDEF
System.out.println(oct2Str("101102103104105106"));

String转8进制ASCII

public static String str2Oct(String str) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < str.length(); i++) {
        char c = str.charAt(i);
        // 这里的第二个参数8表8进制
        sb.append(Integer.toString(c, 8));
        // 或者直接用toOctalString方法转8进制
        // sb.append(Integer.toOctalString(c));
    }
    return sb.toString();
}
 
// 结果为101102103104105106
System.out.println(str2Oct("ABCDEF"));

参考链接:
二、八、十、十六进制转换(图解篇)
https://tool.oschina.net/apidocs/apidoc?api=jdk-zh
java八进制、十进制、十六进制(hex)ASCII码字符串和String互转
Java字节、十进制、十六进制、字符串之间的相互转换
java byte[]与十六进制字符串相互转换
Java中二进制字节与十六进制互转
String.getBytes和new String 出现乱码问题分析
Android String通过蓝牙串口byte[]传送后转成String

上一篇下一篇

猜你喜欢

热点阅读