减少 if-elseif 语句的聪明方法



我开发了一个代码来将SpinBox限制为字母而不是整数。一切正常,但如果有任何聪明的方法,我想减少 if-elseif 语句。这是代码

std::string AlphaSpinBox::textFromValue(int value) 
{
    // I feel the code is Ok but willing to change it if there is a better way.
    // value is restricted [0-25] inclusive. 
    std::string str("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    return std::string(str[value]);
}
int AlphaSpinBox::valueFromText(std::string &text) 
{
    // can I shorten the following?!
    // text is solely one letter (i.e. either upper or lower)
    if(text == 'A' || text == 'a')
        return 0;
    else if(text == 'B' || text == 'b' )
        return 1;
    else if(text == 'C' || text == 'c')
        return 2;
    else if(text == 'D' || text == 'd')
        return 3;
    ... to z letter
}

怎么样:

 if (text.size()>0 && std::isalpha(text[0]))
     return std::toupper(text[0])-'A'; 
 else return -1;    // or throw an exception 

这是一个在线演示。

工作原理:它首先检查字符串是否不为空,以及第一个字符是否是字母(带isalpha()(。 如果它有效,因为您在小写和大写之间没有区别,我们将 char 转换为 toupper() . 由于您的返回值是按字母顺序排列的,因此我们只需要减去第一个字母。

根据 ASCII 表,每个字母都有一个整数值。如果你查一下,你还会发现这些字母方便地放在表格中:a到z都直接相互跟随,A到Z也是如此。

您可以先确定小写或大写,然后返回 text[0] - 'a'text[0] - 'b'

您可以通过利用字符串的 find 成员函数并稍微更改函数签名来消除 valueFromText 函数中的多个 if 语句:

int valueFromText(const std::string& s, char c) {
    return s.find(std::toupper(static_cast<unsigned char>(c)));
}

下面是,也许,更容易理解的一个:

int AlphaToNumeric(string &value)
{
    return (value.front() >= 'A' && value.front() <= 'Z') ? value.front() - 'A' : (value.front() >= 'a' && value.front() <= 'z') ? value.front() - 'a' : -1;
}

或:

int AlphaToNumeric(string &value)
{
    return (value.front() >= 65 && value.front() <= 90) ? value.front() - 65 : (value.front() >= 97 && value.front() <= 122) ? value.front() - 97 : -1;
}
不确定

这是否限定为"聪明",但假设你只想看text的第一个字符,你可以简单地做

#include <string>
#include <cctype>
int AlphaSpinBox::valueFromText(const std::string &text) 
{
     std::string str("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
     int retval = -2;
     if (text.size() > 0)
     {
         char c = std::toupper(text[0]);
         std::size_t index = str.find(c);
         retval = (index != std::string::npos) ? int(index) : -1;
     }
     return retval;
}

与原始问题中的代码不同,这将编译(因为它尝试转换字符串中的第一个字符,而不是整个字符串(。 但是,它也执行更多检查,因此如果给定长度为零的字符串,-1如果字符串中的第一个字符不是字母,它将返回-2

如果您假设一个字符集(大写(字母按顺序出现,则可以简化得多。 此假设并非对所有标准化字符集都严格成立,但对于现代系统通常是正确的。

#include <string>
#include <cctype>
int AlphaSpinBox::valueFromText(const std::string &text) 
{
     int retval = -2;
     if (text.size() > 0)
     {
         int c = std::toupper(text[0]);
         retval = std::isupper(c) ? c - 'A' : -1;
     }
     return retval;
}

选择使用其中一个版本或另一个版本取决于代码永远不会移植到具有字母非连续字符集的系统的信心级别。

编写一个带有静态成员(std::map - look up table(的小类或结构,以及一些充当包装器的静态方法,绝对适用于您的情况。代码的使用相当干净,可读,易于使用,应该是可移植和可重用的。


注意: - 如果系统的字符代码是按顺序定义的,这将起作用;否则,您将需要一些其他机制来initialize静态映射。


AlphaSpinBox.h

#ifndef ALPHA_SPIN_BOX_H
#define ALPHA_SPIN_BOX_H
#include <string>
#include <cctype>
#include <map>
struct AlphaSpinBox {    
    // static table
    static std::map<unsigned, std::string> table_;    
    // Must be called first
    static void initializeMap();    
    // helper function
    static std::string toUpper( const std::string& str );    
    // get string from value
    static std::string textFromValue( const unsigned& val );        
    // get value from string
    static unsigned valueFromText( const std::string& text );
    // other member's, functions etc. that you may have for this class
};
#endif // !ALPHA_SPIN_BOX_H

阿尔法旋转盒.cpp

#include "AlphaSpinBox.h"
// define static member
std::map<unsigned, std::string> AlphaSpinBox::table_;
void AlphaSpinBox::initializeMap() {
    // Could do some checks here to see if this function has not been called
    // then display a message to the user that this function needs to be called first;
    // and to check if it has already been called once before; warning the user
    // that this method should only initialize the map once per application run.
    static char c = 'A';
    static std::string str;
    for ( unsigned n = 0; n < 26; n++ ) {
        str.assign( &c );
        table_.insert( std::make_pair( n, str ) );
        c++;
    }
}
std::string AlphaSpinBox::toUpper( const std::string& str ) {
    std::string result = str;
    std::transform( str.begin(), str.end(), result.begin(), ::toupper );
    return result;
}
std::string AlphaSpinBox::textFromValue( const unsigned& val ) {
    // you could check to see if val is within range before returning...
    return table_[val];
}
unsigned AlphaSpinBox::valueFromText( const std::string& text ) {
    std::string upper = toUpper( text );
    for ( auto pair : table_ ) {
        if ( upper == pair.second ) {
            return pair.first;
        }
    }
    return -1;
}

主.cpp

#include <string>
#include <iostream>
#include "AlphaSpinBox.h"
int main() {
    // Must Be Called First
    AlphaSpinBox::initializeMap();
    // Remember that the map first entry's key starts at 0 and not 1
    std::cout << "The number 8 has letter: " 
              << AlphaSpinBox::textFromValue( 8 ) 
              << std::endl;
    std::cout << "The letter Q has value: " 
              << AlphaSpinBox::valueFromText( std::string( "Q" ) ) 
              << std::endl;
    // check case for lower cases being converted to upper case
    std::cout << "The letter j has value: " 
              << AlphaSpinBox::valueFromText( std::string( "j" ) ) 
              << std::endl;
    std::cout << "nPress any key and enter to quit." << std::endl;
    char q;
    std::cin >> q;
    return 0;
}

最新更新