本文同时发表于https://github.com/zhangyachen/zhangyachen.github.io/issues/9

发表于 2016-03-06
| 分类于
编程

核心代码如下:

数据解析时,python可以相互转换各种数据类型。最近在斯坦福公开课《密码学》网站上面做题发现,我对数据转换很不熟悉,写下日志记下用法。
导航

/* {{{ php_trim()
 * mode 1 : trim left
 * mode 2 : trim right
 * mode 3 : trim left and right
 * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
 */
PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC)
{
    register int i;
    int trimmed = 0;
    char mask[256];

    if (what) {
        php_charmask((unsigned char*)what, what_len, mask TSRMLS_CC);
    } else {
        php_charmask((unsigned char*)" \n\r\t\v\0", 6, mask TSRMLS_CC);
    }
        //从左开始
    if (mode & 1) {
        for (i = 0; i < len; i++) {
            if (mask[(unsigned char)c[i]]) {        //该位置有第二个参数对应的值
                trimmed++;
            } else {
                break;
            }
        }
        len -= trimmed;
        c += trimmed;
    }
    if (mode & 2) {
        for (i = len - 1; i >= 0; i--) {
            if (mask[(unsigned char)c[i]]) {
                len--;
            } else {
                break;
            }
        }
    }

    if (return_value) {
                //把c指针现在指向的位置以后的len个字符返回
        RETVAL_STRINGL(c, len, 1);
    } else {
        return estrndup(c, len);
    }
    return "";
}

数字
字符串
字节码

可以看出,在php_trim函数内部调用了php_charmask函数

到数字
进制转换
字符转整数
字节串转整数

/* {{{ php_charmask
 * Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
 * it needs to be incrementing.
 * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
 */
static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC)
{
    unsigned char *end;
    unsigned char c;
    int result = SUCCESS;

    memset(mask, 0, 256);      //初始化一个长度为256的hash表
    for (end = input+len; input < end; input++) {
        c=*input;
        if ((input+3 < end) && input[1] == '.' && input[2] == '.'
                && input[3] >= c) {
            memset(mask+c, 1, input[3] - c + 1);
            input+=3;
        } else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
            /* Error, try to be as helpful as possible:
               (a range ending/starting with '.' won't be captured here) */
            if (end-len >= input) { /* there was no 'left' char */
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
                result = FAILURE;
                continue;
            }
            if (input+2 >= end) { /* there is no 'right' char */
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
                result = FAILURE;
                continue;
            }
            if (input[-1] > input[2]) { /* wrong order */
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
                result = FAILURE;
                continue;
            }
            /* FIXME: better error (a..b..c is the only left possibility?) */
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range");
            result = FAILURE;
            continue;
        } else {
                        //对应的位置为1
            mask[c]=1;
        }
    }
    return result;
}

到字符串
str()
字符串编码解码
decode(‘hex’)

可以看出trim函数的逻辑:
1 声明一个长度为256的hash表。
2
将character_mask中每个字节转化为ascii码,将hash表中ascii码对应key的value设置为1。
3
从头部遍历str中每个字节,若遍历到字节对应的ascii码在hash表中存在,则str长度位置减1;若不存在,就中断循环。
4 从尾部遍历str中每个字节,逻辑同3。

到字节码
数字转字符串
字符串转字节串
no

案例分析:
trim(“广东省”,”省”)导致乱码

还有常见的单个字符转换
函数
功能
记忆口诀
备注

首先获得”广东省”的十六进制表示

chr
数字转成对应的ascii字符
chr长得很像char,因此转成char
范围为0~255

<?php
// 文件utf-8编码
// 获取字符串编码
function get_hex_str($str) {
    $hex_str = '';
    for ($i = 0; $i < strlen($str); $i ++) {
        $ord = ord($str[$i]);//转换为ascii码
        $hex_str .= sprintf("\x%02X", $ord);//以十六进制输出,2为指定的输出字段的宽度.如果位数小于2,则左端补0
    }
    return $hex_str;
}

ord
单个字符转对应ascii序号
digit为最后一个字母

$str = “广东省”;
printf(“str[%s] hex_str[%s]\n”, \(str,
get_hex_str(\)str));

进制转换
10进制转16进制:
hex(16) ==> 0x10

\(str = trim(\)str, “省”);
printf(“str[%s] hex_str[%s]\n”, \(str,
get_hex_str(\)str));

16进制转10进制:
int(STRING,BASE)将字符串STRING转成十进制int,其中STRING的基是base。该函数的第一个参数是字符串
int(‘0x10’, 16) ==> 16

输出:
str[广东省]
hex_str[\xE5\xB9\xBF\xE4\xB8\x9C\xE7\x9C\x81]
str[广hex_str[\xE5\xB9\xBF\xE4\xB8]

类似的还有八进制oct(), 二进制bin()
16进制字符串转成二进制
hex_str=’00fe’bin(int(‘1’+hex_str, 16))[3:] #含有前导0# 结果
‘0000000011111110’bin(int(hex_str, 16))[2:] #忽略前导0# 结果
‘11111110’

utf-8编码下汉字对应三个字节,“东”的编码为e4 b8 9c,“省”的编码为e7 9c
81。
trim(“广东省”, “省”);
函数处理时不是以我们看到的中文字符为一个单位,而是以字节为单位。
相等于从e5 b9 bf e4 b8 9c e7 9c 81开头和结尾去掉包含在e7 9c
81的字节,这样“东”的第三个字节就会被切掉,就会有上述的输出了。

二进制字符串转成16进制字符串
bin_str=’0b0111000011001100’hex(int(bin_str,2))# 结果 ‘0x70cc’

如果想将中文字符串中部分字符去掉,建议使用str_replace。

字符to整数
10进制字符串:
int(’10’) ==> 10

16进制字符串:
int(’10’, 16) ==> 16# 或者int(‘0x10’, 16) ==> 16

字节串to整数
使用网络数据包常用的struct,兼容C语言的数据结构struct中支持的格式如下表
Format
C-Type
Python-Type
字节数
备注

x
pad byte
no value
1

c
char
string of length 1
1

b
signed char
integer
1

B
unsigned char
integer
1

?
_Bool
bool
1

h
short
integer
2

H
unsigned short
integer
2

i
int
integer
4

I
unsigned int
integer or long
4

l
long
integer
4

L
unsigned long
long
4

q
long long
long
8
仅支持64bit机器

Q
unsigned long long
long
8
仅支持64bit机器

f
float
float
4

d
double
float
8

s
char[]
string
1

p
char[]
string
1(与机器有关)
作为指针

P
void *
long
4
作为指针

对齐方式:放在第一个fmt位置
CHARACTER
BYTE ORDER
SIZE
ALIGNMENT

@
native
native
native

=
native
standard
none

<
little-endian
standard
none

big-endian
standard
none

!
network (= big-endian)
standard
none

转义为short型整数:
struct.unpack(‘<hh’, bytes(b’\x01\x00\x00\x00′)) ==> (1, 0)

转义为long型整数:
struct.unpack(‘<L’, bytes(b’\x01\x00\x00\x00′)) ==> (1,)

整数to字节串
转为两个字节:
struct.pack(‘<HH’, 1,2) ==> b’\x01\x00\x02\x00′

转为四个字节:
struct.pack(‘<LL’, 1,2) ==>
b’\x01\x00\x00\x00\x02\x00\x00\x00′

整数to字符串
直接用函数
str(100)

字符串to字节串
我用c++实现的encode(hex)和decode(hex)decode和encode区别
decode函数是重新解码,把CT字符串所显示的69dda8455c7dd425【每隔两个字符】解码成十六进制字符\x69\xdd\xa8\x45\x5c\x7d\xd4\x25
CT=’69dda8455c7dd425’print “%r”%CT.decode(‘hex’)

encode函数是重新编码,把CT字符串所显示的69dda8455c7dd425【每个字符】编码成acsii值,ascii值为十六进制显示,占两位。执行下列结果显示36396464613834353563376464343235等价于将CT第一个字符’6’编码为0x36h
第二个字符’9’编码为0x39h
CT=’69dda8455c7dd425’print “%r”%CT.encode(‘hex’)

可以理解为:decode解码,字符串变短一半,encode编码,字符串变为两倍长度
decode(‘ascii’)解码为字符串Unicode格式。输出带有’u’encode(‘ascii’),编码为Unicode格式,其实python默认处理字符串存储就是Unicode,输出结果估计和原来的字符串一样。
字符串编码为字节码:
’12abc’.encode(‘ascii’) ==> b’12abc’

数字或字符数组:
bytes([1,2, ord(‘1’),ord(‘2′)]) ==> b’\x01\x0212’

16进制字符串:
bytes().fromhex(‘010210′) ==> b’\x01\x02\x10’

16进制字符串:
bytes(map(ord, ‘\x01\x02\x31\x32′)) ==> b’\x01\x0212’

16进制数组:
bytes([0x01,0x02,0x31,0x32]) ==> b’\x01\x0212′

字节串to字符串
字节码解码为字符串:
bytes(b’\x31\x32\x61\x62′).decode(‘ascii’) ==> 12ab

字节串转16进制表示,夹带ascii:
str(bytes(b’\x01\x0212′))[2:-1] ==> \x01\x0212

字节串转16进制表示,固定两个字符表示:
str(binascii.b2a_hex(b’\x01\x0212′))[2:-1] ==> 01023132

字节串转16进制数组:
[hex(x) for x in bytes(b’\x01\x0212′)] ==> [‘0x1’, ‘0x2’,
‘0x31’, ‘0x32’]

问题:什么时候字符串前面加上’r’、’b’、’r’,其实官方文档有写。我认为在Python2中,r和b是等效的。
The Python 2.x documentation:
A prefix of ‘b’ or ‘B’ is ignored in Python 2; it indicates that the
literal should become a bytes literal in Python 3 (e.g. when code is
automatically converted with 2to3). A ‘u’ or ‘b’ prefix may be followed
by an ‘r’
prefix.‘b’字符加在字符串前面,对于python2会被忽略。加上’b’目的仅仅为了兼容python3,让python3以bytes数据类型(0~255)存放这个字符、字符串。

The Python 3.3 documentation states:
Bytes literals are always prefixed with ‘b’ or ‘B’; they produce an
instance of the bytes type instead of the str type. They may only
contain ASCII characters; bytes with a numeric value of 128 or greater
must be expressed with
escapes.数据类型byte总是以’b’为前缀,该数据类型仅为ascii。

下面是stackflow上面一个回答。我觉得不错,拿出来跟大家分享
In Python 2.x
Pre-3.0 versions of Python lacked this kind of distinction between text
and binary data. Instead, there was:
unicode = u’…’ literals = sequence of Unicode characters = 3.x str
str = ‘…’ literals = sequences of confounded bytes/charactersUsually
text, encoded in some unspecified encoding.But also used to represent
binary data like struct.pack output.

Python 3.x makes a clear distinction between the types:
str = ‘…’ literals = a sequence of Unicode characters (UTF-16 or UTF-32,
depending on how Python was compiled)
bytes = b’…’ literals = a sequence of octets (integers between 0 and
255)

CPP实现encode
就是做个笔记,毕竟在做题Cryptography时候用c++写字符串的处理很蛋疼!为了防止再次造轮子,记下来。

include <cstring> //用到strlen函数static unsigned char ByteMap[] = { ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’,’9′, ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’ };unsigned char hex_2_dec(unsigned char c){ if(c >= ‘0’ && c <= ‘9’) return c – ‘0’; if(c >= ‘a’ && c <= ‘f’) return c – ‘a’ + 10;}void str_encode(unsigned char *src, unsigned char dest, int len_of_src) { // 使用注意:dest_len >= 2len_src +1,最后一位是存放’\0’。 int t1; for (int i = 0; i < len_of_src; ++i) { t1 = (int) src[i]; dest[2 * i] = ByteMap[t1 / 16]; dest[2 * i + 1] = ByteMap[t1 % 16]; } dest[2 * len_of_src] = 0; //必须填充最后一个为’\0′}void str_decode(unsigned char *src,unsigned char *dest){ int len_of_src=strlen((char )src); unsigned char t1; for(int i=1;i<=len_of_src;i+=2){ t1=hex_2_dec(src[i-1]); t1= 16t1 + hex_2_dec(src[i]); dest[i/2]=t1; }}

鸣谢本文转载自csdn博客的《python常用的十进制、16进制、字符串、字节串之间的转换》

#python
#转载

admin

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注