package live.every.day.ProgrammingDesign.CodingInterviewGuide.String;

/**
 * 将整数字符串转成整数值
 *
 * 【题目】
 * 给定一个字符串str,如果str 符合日常书写的整数形式,并且属于32位整数的范围,返回str所代表的整数值,否则返回0。
 *
 * 【难度】
 * 中等
 *
 * 【解答】
 * 解决本题的方法有很多,本文仅提供一种供读者参考。首先检查str是否符合日常书写的整数形式,具体判断如下:
 *
 * 1.如果str不以"-"开头,也不以数字字符开头,例如,str=="A12”,返回false。
 * 2.如果str以"-"开头。但是str的长度为1,即str=="-",返回false。如果str的长度大于1,但是"-"的后面紧跟着"0",例如,
 * str=="-0"或"-012",返回false。
 * 3.如果str以"0"开头,但是str的长度大于1,例如,str=="023",返回false。
 * 4.如果经过步骤1~步骤3都没有返回,接下来检查str[l..N-1]是否都是数字字符,如果有一个不是数字字符,返回false。如果都
 * 是数字字符,说明str符合日常书写,返回true。
 *
 * 具体检查过程请参看如下代码中的isValid方法。
 *
 * 如果str不符合日常书写的整数形式,根据题目要求,直按返回0即可。如果符合,则进行如下转换过程:
 *
 * 1.生成4个变量。布尔型常量posi,表示转换的结果是负数还是非负数,这完全由str开头的字符决定,如果以“-”开头,那么转换的
 * 结果一定是负数,则posi为false,否则posi为true。整型常量minq,minq等于Integer.MIN_VALUE/10,即32位整数最小值
 * 除以10得到的商,其意义稍后说明。整型常量minr,minr等于Integer.MINVALUE%10,即32位整数最小值除以10得到的余数,其
 * 意义稍后说明。整型变量res,转换的结果,初始时res=0。
 * 2.32位整数的最小值为-2147483648,32位整数的最大值为2147483647。可以看出,最小值的绝对值比最大值的绝对值大1,所以
 * 转换过程中的绝对值一律以负数的形式出现,然后根据posi决定最后返回什么。也就是说,既然负数比正数拥有更大的绝对值范围,那
 * 么转换过程中一律以负数的形式记录绝对值,最后再决定返回的数到底是什么。
 * 3.如果str以"-"开头,从str[1]开始从左往右遍历str,否则从str[O]开始从左往右遍历str。出现任何一种溢出情况时,直接返
 * 回0。
 * 4.遍历后得到的res根据posi的符号决定返回值。如果posi为true,说明结果应该返回正,否则说明应该返回负。如果res正好是
 * 32位整数的最小值,同时又有posi为true,说明溢出,直接返回0。
 *
 * 全部过程请参看如下代码中的convert方法。
 *
 * @author Created by LiveEveryDay
 */
public class IntStr2Int {

    public static boolean isValid(char[] chas) {
        if (chas[0] != '-' && (chas[0] < '0' || chas[0] > '9')) {
            return false;
        }
        if (chas[0] == '-' && (chas.length == 1 || chas[1] == '0')) {
            return false;
        }
        if (chas[0] == '0' && chas.length > 1) {
            return false;
        }
        for (int i = 1; i < chas.length; i++) {
            if (chas[i] < '0' || chas[i] > '9') {
                return false;
            }
        }
        return true;
    }

    public static int convert(String str) {
        if (str == null || str.equals("")) {
            return 0;
        }
        char[] chas = str.toCharArray();
        if (!isValid(chas)) {
            return 0;
        }
        boolean posi = chas[0] != '-';
        int minq = Integer.MIN_VALUE / 10;
        int minr = Integer.MIN_VALUE % 10;
        int res = 0;
        int cur = 0;
        for (int i = posi ? 0 : 1; i < chas.length; i++) {
            cur = '0' - chas[i];
            if ((res < minq) || (res == minq && cur < minr)) {
                return 0;
            }
            res = res * 10 + cur;
        }
        if (posi && res == Integer.MIN_VALUE) {
            return 0;
        }
        return posi ? -res : res;
    }

    public static void main(String[] args) {
        String str = "-123";
        System.out.printf("The number is: %d", convert(str));
    }

}

// ------ Output ------
/*
The number is: -123
*/