劍指Offer(Java版):把字符串轉換成整數

題目:實現一個函數 stringToInt,實現把字符串轉換成整數這個功能,不能使用 atoi 或者其餘相似的庫函數。

題目解析

這看起來是很簡單的題目,實現基本功能 ,大部分人都能用10行以內的代碼解決。但是,當咱們要把不少特殊狀況即測試用例都考慮進去,卻不是件容易的事。解決數值轉換問題自己並不難,但我但願在 寫轉換數值的代碼以前,應聘者至少能把空指針,空字符串」「,正負號,溢出等方方面面的測試用例都考慮到,而且在寫代碼的時候對這些特殊的輸入都定義好合 理的輸出。固然,這些輸出並不必定要和atoi徹底保持一致,但必需要有顯式的說明,和麪試官溝通好。java

這個應聘者最大的問題就是尚未養成在寫代碼以前考慮全部可能的測試用例的習慣,邏輯不夠嚴謹,所以一開始的代碼只處理了最基本的數值轉換。後來我 每次提醒他一處特殊的測試用例以後,他改一處代碼。儘管他已經作了兩次修改,但仍然有很多很明顯的漏洞,特殊輸入空字符串」「,邊界條件好比最大的正整數 與最小的負整數等。因爲這道題思路自己不難,所以我但願他把問題考慮得很可能周到,代碼儘可能寫完整。git

歸納起來有幾種狀況面試

1)字符串開頭是「+」號或「-」號的處理ide

2)非法字符的判斷(不是數字)函數

3)整數溢出問題。測試

看看Java函數庫中的Integer.parseInt(String sting)的源碼如何處理這些問題的。this

/**
 * Parses the specified string as a signed decimal integer value. The ASCII
 * character \u002d ('-') is recognized as the minus sign.
 *
 * @param string
 *			the string representation of an integer value.
 * @return the primitive integer value represented by {@code string}.
 * @throws NumberFormatException
 *			 if {@code string} cannot be parsed as an integer value.
 */
public static int parseInt(String string) throws NumberFormatException {
  return parseInt(string, 10);
}
 
/**
 * Parses the specified string as a signed integer value using the specified
 * radix. The ASCII character \u002d ('-') is recognized as the minus sign.
 *
 * @param string
 *			the string representation of an integer value.
 * @param radix
 *			the radix to use when parsing.
 * @return the primitive integer value represented by {@code string} using
 *		 {@code radix}.
 * @throws NumberFormatException
 *			 if {@code string} cannot be parsed as an integer value,
 *			 or {@code radix < Character.MIN_RADIX ||
 *			 radix > Character.MAX_RADIX}.
 */
public static int parseInt(String string, int radix) throws NumberFormatException {
  if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
    throw new NumberFormatException("Invalid radix: " + radix);
  }
  if (string == null) {
    throw invalidInt(string);
  }
  int length = string.length(), i = 0;
  if (length == 0) {
    throw invalidInt(string);
  }
  boolean negative = string.charAt(i) == '-';
  if (negative && ++i == length) {
    throw invalidInt(string);
  }
 
  return parse(string, i, radix, negative);
}
 
private static int parse(String string, int offset, int radix, boolean negative) throws NumberFormatException {
  int max = Integer.MIN_VALUE / radix;
  int result = 0, length = string.length();
  while (offset < length) {
    int digit = Character.digit(string.charAt(offset++), radix);
    if (digit == -1) {
      throw invalidInt(string);
    }
    if (max > result) {
      throw invalidInt(string);
    }
    int next = result * radix - digit;
    if (next > result) {
      throw invalidInt(string);
    }
    result = next;
  }
  if (!negative) {
    result = -result;
    if (result < 0) {
      throw invalidInt(string);
    }
  }
  return result;
}

 parseInt(String string,  int  radix)判斷了spa

1) radix進制超出範圍 ( Character. MIN_RADIX  = 2, Character. MAX_RADIX )=36).net

2)字符串爲null指針

3)字符串長度爲空

4)字符串第一位爲「-」且只有一位

  沒有異常以後進行 parse(String string,  int  offset,  int  radix,  boolean  negative) 判斷,參數即字符串,偏移量,進制, negative (若是開頭沒有「-」則offset=0,negative=false,不然爲offset=1,neagtive=true)

   在 parse(String string,  int  offset,  int  radix,  boolean  negative)主要進行了溢出的判斷。利用 offset++來控制移動,  在 while  (offset < length)  循環中 直到倒數 第二位的時候,若是已經 小於  max = Integer.MIN_VALUE / radix 的話代表必定會溢出。例如"-2147483648"

倒數第二位的時候 :result= -214748364,max = -214748364,max>result不成立代表 能夠進行最後一位的處理。

以下代碼:

package cglib;


public class jiekou {
    public static void main(String[] args) {
        // TODO 自動生成的方法存根
        try {
          System.out.println(parseInt("cao21'''474fefda8364fe7"));
          //System.out.println(parseInt(""));
          System.out.println(parseInt(null));
          System.out.println(parseInt("-2147483648"));
          System.out.println(parseInt("-2147483651"));
          System.out.println(parseInt("-2147483648"));
          System.out.println(parseInt("-21474836410"));
        } catch (MyException e) {
          // TODO 自動生成的 catch 塊
          e.printStackTrace();
        }
    
      }
    
      private static int parseInt(String string) throws MyException {
        /* 異常狀況1:字符串爲null */
        if (string == null) {
          throw new MyException("字符串爲null!");
        }
        int length = string.length(), offset = 0;
        /* 異常狀況2:字符串長度爲0 */
        if (length == 0) {
          throw new MyException("字符串長度爲0!");
        }
        boolean negative = string.charAt(offset) == '-';
        /* 異常狀況3:字符串爲'-' */
        if (negative && ++offset == length) {
          throw new MyException("字符串爲:'-'!");
        }
        int result = 0;
        char[] temp = string.toCharArray();
        while (offset < length) {
          char digit = temp[offset++];
          if (digit <= '9' && digit >= '0') {
            int currentDigit = digit - '0';
            /*
             * 異常狀況4:已經等於Integer.MAX_VALUE / 10,判斷要添加的最後一位的狀況:
             * 若是是負數的話,最後一位最大是8 若是是正數的話最後一位最大是7
             */
            if (result == Integer.MAX_VALUE / 10) {
    
              if ((negative == false && currentDigit > 7)
                  || (negative && currentDigit > 8)) {
                throw new MyException("溢出!");
              }
              /*
               * 異常狀況5:已經大於Integer.MAX_VALUE / 10
               * 不管最後一位是什麼都會超過Integer.MAX_VALUE
               */
            } else if (result > Integer.MAX_VALUE / 10) {
              throw new MyException("溢出!");
            }
    
            int next = result * 10 + currentDigit;
            result = next;
          }
        }
        if (negative) {
          result = -result;
        }
        return result;
      }
    
    }
    
    /* 自定義異常 */
    @SuppressWarnings("serial")
    class MyException extends Exception {
      /**
       *
       */
      @SuppressWarnings("unused")
    private static  long serialVersionUID = 1749149488419303367L;
      String message;
    
      public MyException(String message) {
        // TODO 自動生成的構造函數存根
        this.message = message;
      }
    
      @Override
      public String getMessage() {
        // TODO 自動生成的方法存根
        return message;
      }
    }
   輸出:

147483647
cglib.MyException: 字符串爲null!
    at cglib.jiekou.parseInt(jiekou.java:25)
    at cglib.jiekou.main(jiekou.java:10)

 

或者:

package cglib;


public class jiekou {
    /**
     * 題目:實現一個函數stringToInt,實現把字符串轉換成整數這個功能,
     * 不能使用atoi或者其餘相似的庫函數。
     *
     * @param num
     * @return
     */
    public static int stringToInt(String num) {
        if (num == null || num.length() < 1) {
            throw new NumberFormatException(num);
        }
        char first = num.charAt(0);
        if (first == '-') {
            return parseString(num, 1, false);
        } else if (first == '+') {
            return parseString(num, 1, true);
        } else if (first <= '9' && first >= '0') {
            return parseString(num, 0, true);
        } else {
            throw new NumberFormatException(num);
        }
    }
    /**
     * 判斷字符是不是數字
     *
     * @param c 字符
     * @return true是,false否
     */
    private static boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }
    /**
     * 對字符串進行解析
     *
     * @param num      數字串
     * @param index    開始解析的索引
     * @param positive 是正數仍是負數
     * @return 返回結果
     */
    private static int parseString(String num, int index, boolean positive) {
        if (index >= num.length()) {
            throw new NumberFormatException(num);
        }
        int result;
        long tmp = 0;
        while (index < num.length() && isDigit(num.charAt(index))) {
            tmp = tmp * 10 + num.charAt(index) - '0';
            // 保證求的得的值不超出整數的最大絕對值
            if (tmp > 0x8000_0000L) {
                throw new NumberFormatException(num);
            }
            index++;
        }
        if (positive) {
            if (tmp >= 0x8000_0000L) {
                throw new NumberFormatException(num);
            } else {
                result = (int) tmp;
            }
        } else {
            if (tmp == 0x8000_0000L) {
                result = 0x8000_0000;
            } else {
                result = (int) -tmp;
            }
        }
        return result;
    }
    public static void main(String[] args) {
      //System.out.println(Integer.parseInt(Integer.MIN_VALUE + ""));
     //   System.out.println(0x8000_0000L);
     //   System.out.println(stringToInt(""));
        System.out.println(stringToInt("123"));
        System.out.println(stringToInt("+123"));
        System.out.println(stringToInt("-123"));
        System.out.println(stringToInt("aaa"));
        System.out.println(stringToInt("+2147483647"));
        System.out.println(stringToInt("-2147483647"));
        System.out.println(stringToInt("+2147483648"));
        System.out.println(stringToInt("-2147483648"));
      System.out.println(stringToInt("+2147483649"));
      System.out.println(stringToInt("-2147483649"));
       System.out.println(stringToInt("+"));
        System.out.println(stringToInt("-"));
    }
    }
    

輸出: Exception in thread "main" java.lang.NumberFormatException: aaa     at cglib.jiekou.stringToInt(jiekou.java:24)     at cglib.jiekou.main(jiekou.java:80) 123 123 -123

相關文章
相關標籤/搜索