⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sflcvsn.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
字号:
/*  ----------------------------------------------------------------<Prolog>-
    Name:       sflcvsn.c
    Title:      Converts a string to a number
    Package:    Standard Function Library (SFL)

    Written:    1996/01/05  iMatix SFL project team <sfl@imatix.com>
    Revised:    1997/09/08

    Copyright:  Copyright (c) 1996-2000 iMatix Corporation
    License:    This is free software; you can redistribute it and/or modify
                it under the terms of the SFL License Agreement as provided
                in the file LICENSE.TXT.  This software is distributed in
                the hope that it will be useful, but without any warranty.
 ------------------------------------------------------------------</Prolog>-*/

#include "prelude.h"                    /*  Universal header file            */
#include "sflconv.h"                    /*  Prototypes for functions         */


/*  ---------------------------------------------------------------------[<]-
    Function: conv_str_number

    Synopsis: Converts a string to a number.  The number format is defined
    by one or more of these flags (you add them to get a flags argument):
    <TABLE>
        FLAG_N_SIGNED       Number is signed.
        FLAG_N_DECIMALS     Number has decimals.
        FLAG_N_ZERO_FILL    Number has leading zeros.
        FLAG_N_THOUSANDS    Number has thousands-separators.
    </TABLE>

    The input string may contain digits, decimal point, thousand separators
    and a sign character or indicator.  Formatting characters are only
    accepted if they correspond to the number format.  A blank string is
    accepted as zero.  A space following digits ends the number; anything
    further is ignored.

    Returns a string of width digits, including leading sign if that is
    required.  Zeroes are signed with a space.  Width must be at least 1.

    If the flag FLAG_N_DECIMALS is set, the last X digits are decimals,
    where X is the value of the decimals argument.  Decimals are then
    accepted or rejected depending on the dec_format:
    <TABLE>
        DECS_SHOW_ALL       Accept decimals.
        DECS_DROP_ZEROS     Accept decimals.
        DECS_HIDE_ALL       Reject decimals.
        DECS_SCIENTIFIC     Accept decimals.
    </TABLE>

    If the flag FLAG_N_SIGNED is set, accepts a leading or trailing sign,
    or a financial negative like this: (123).

    Returns a pointer to the formatted string, or null if the string was
    rejected.  These are the possible reasons for rejection:
    <LIST>
        - input number is too large for specified width;
        - input number is signed when no sign is allowed;
        - input number decimals when none are allowed;
        - input number has more decimals than are allowed;
        - more than one sign character in number;
        - malformed financial negative '(123)';
        - more than one decimal point in number;
        - thousand seps when FLAG_N_THOUSANDS is cleared or FLAG_N_ZERO_FILL
          is set (this overrides FLAG_N_THOUSANDS);
        - junk in input string (unrecognised character).
    </LIST>
    ---------------------------------------------------------------------[>]-*/

char *
conv_str_number (
    const char *string,                 /*  String to convert                */
    int   flags,                        /*  Number field flags               */
    char  dec_point,                    /*  Decimal point: '.' or ','        */
    int   decimals,                     /*  Number of decimals, or 0         */
    int   dec_format,                   /*  How are decimals shown           */
    int   width                         /*  Output field width, > 0          */
)
{
    static char
        number [FORMAT_MAX + 1];        /*  Cleaned-up return string         */
    int
        digits,                         /*  Number of digits read so far     */
        decs_wanted = decimals;         /*  Number of decimals wanted        */
    char
       *dest,                           /*  Store formatted number here      */
        sign_char,                      /*  Number's sign: ' ', '+', '-'     */
        sep_char,                       /*  Thousands separator '.' or ','   */
        decs_seen,                      /*  Number of decimals output        */
        ch;                             /*  Next character in picture        */
    Bool
        have_point,                     /*  Have we seen a decimal point     */
        have_zero,                      /*  TRUE if number is all zero       */
        end_loop;                       /*  Flag to break out of scan loop   */

    ASSERT (width <= FORMAT_MAX);
    ASSERT (width > 0);
    ASSERT (dec_point == '.' || dec_point == ',');

    conv_reason = 0;                    /*  No conversion errors so far      */

    /*  ---------------------------------   Prepare to copy digits  ---------*/

    if ((flags & FLAG_N_THOUSANDS) && !(flags & FLAG_N_ZERO_FILL))
        sep_char = dec_point == '.'? ',': '.';
    else
        sep_char = ' ';                 /*  Reject any thousands separator   */

    /*  ---------------------------------   Copy the digits  ----------------*/

    digits     = 0;                     /*  No digits loaded yet             */
    decs_seen  = 0;                     /*  No decimals output yet           */
    sign_char  = ' ';                   /*  Final sign character '+' or '-'  */
    end_loop   = FALSE;                 /*  Flag to break out of scan loop   */
    have_point = FALSE;                 /*  No decimal point seen            */
    have_zero  = TRUE;                  /*  So far, it's zero                */

    dest = number;                      /*  Scan through number              */
    while (*string)
      {
        ch = *string++;
        switch (ch)
          {
            case '9':
            case '8':
            case '7':
            case '6':
            case '5':
            case '4':
            case '3':
            case '2':
            case '1':
                have_zero = FALSE;
            case '0':
                digits++;
                *dest++ = ch;
                if (have_point)
                    ++decs_seen;
                break;

            case '-':
            case '+':
            case '(':
                if (sign_char != ' ')
                  {
                    conv_reason = CONV_ERR_MULTIPLE_SIGN;
                    return (NULL);      /*  More than one sign char          */
                  }
                else
                if (flags & FLAG_N_SIGNED)
                    sign_char = ch;
                else
                  {
                    conv_reason = CONV_ERR_SIGN_REJECTED;
                    return (NULL);      /*  Number may not be signed         */
                  }
                break;

            case ')':
                if (sign_char == '(')
                    sign_char = '-';
                else
                  {
                    conv_reason = CONV_ERR_SIGN_BAD_FIN;
                    return (NULL);      /*  Malformed financial negative     */
                  }
                break;

            case ' ':                   /*  Space ends number after digits   */
                end_loop = (digits > 0);
                break;

            default:
                if (ch == dec_point)
                  {
                    if (have_point)
                      {
                        conv_reason = CONV_ERR_MULTIPLE_POINT;
                        return (NULL);  /*  More than one decimal point      */
                      }
                    else
                    if (flags & FLAG_N_DECIMALS)
                        have_point = TRUE;
                    else
                      {
                        conv_reason = CONV_ERR_DECS_REJECTED;
                        return (NULL);  /*  No decimals are allowed          */
                      }
                  }
                else
                if (ch != sep_char)     /*  We allow sep chars anywhere      */
                  {
                    conv_reason = CONV_ERR_INVALID_INPUT;
                    return (NULL);      /*    else we have junk              */
                  }
          }
        if (end_loop)
            break;
      }

    /*  ---------------------------------   Post-format the result  ---------*/

    if (flags & FLAG_N_DECIMALS)
      {
        ASSERT (width > decs_wanted);   /*  At least decimals + 1 digit      */

        if (dec_format == DECS_HIDE_ALL)
          {
            if (have_point)
              {
                conv_reason = CONV_ERR_DECS_HIDDEN;
                return (NULL);          /*  No decimals are allowed          */
              }
          }
        while (decs_seen < decs_wanted) /*  Supply missing decimals          */
          {
            digits++;
            *dest++ = '0';
            decs_seen++;
          }
        if (decs_seen > decs_wanted)
          {
            conv_reason = CONV_ERR_DECS_OVERFLOW;
            return (NULL);              /*  More decimals than allowed       */
          }
      }
    else
        decs_wanted = 0;

    *dest = 0;                          /*  Terminate the string nicely      */
    if (digits > width)
      {
        conv_reason = CONV_ERR_TOO_MANY_DIGITS;
        return (NULL);                  /*  Overflow -- number too large     */
      }

    /*  Supply leading zeroes                                                */
    if (digits < width)
      {
        /*  Shift number and null to right of field                          */
        memmove (number + (width - digits), number, digits + 1);
        memset  (number, '0', width - digits);
      }

    /*  Store sign if necessary                                              */
    if (flags & FLAG_N_SIGNED)
      {
        ASSERT (width > 1);             /*  At least sign + 1 digit          */
        if (number [0] != '0')
          {
            conv_reason = CONV_ERR_TOO_MANY_DIGITS;
            return (NULL);              /*  Overflow -- no room for sign     */
          }
        if (sign_char == '(')
          {
            conv_reason = CONV_ERR_SIGN_BAD_FIN;
            return (NULL);              /*  Malformed financial negative     */
          }
        else
        if (sign_char == ' ')
            sign_char = '+';

        if (have_zero)
            number [0] = ' ';           /*  Store sign                       */
        else
            number [0] = sign_char;
      }

    return (number);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -