2

我有一个字符串为“1.0.0”,我想提取“1”、“0”和“0”。如果最后一个零不存在,则默认情况下字符串必须存储 0:

verstr.substr(0,verstr.find(".");

上面的语句可以找到第一个数字“1”,但是,我想不出提取字符串剩余部分的解决方案。

在此之后,我将其转换为 long :

        va = atol(verstr.substr(0,verstr.find(".")).c_str());

所以我想要 va 中的“1”,“vb”中的 0 等等

谢谢。

4

7 回答 7

4

C++11 解决方案:

#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main(int, char **) {
    string version("1.2.3");
    match_results<string::const_iterator> m;
    regex re("([0-9]+)\\.([0-9]+)(\\.([0-9]+))?");
    if (regex_match(version, m, re)) {
        int major = stoi(m[1].str()),
            minor = stoi(m[2].str()),
            rev = stoi(m[4].str().length() == 0 ? 0 : m[4].str());
        cout << "major: " << major << endl;
        cout << "minor: " << minor << endl;
        cout << "rev: " << rev << endl;
    } else {
        cout << "no match\n";
    }
}

使用的正则表达式是([0-9]+)\.([0-9]+)(\.([0-9]+))?并且分解如下:

[0-9]+匹配一位或多位数字

\.匹配文字点。

?在最后一个表达式之后表示它是可选的

(包含在和)捕获组中的表达式。此表达式中有五个捕获组:

0 - 总是匹配整个字符串 - 我们不使用它。

1 - 匹配主要版本号。

2 - 匹配次要版本号。

3 - 匹配一个点后跟修订号 - 我们不使用它,但它是必要的,因为我们使用括号后跟 a?使整个组可选。

4 - 匹配修订号。

于 2012-08-01T13:40:14.460 回答
3

不确定我是否理解您的需求,如果您想以字符串形式检索数字,并且最少需要 x 个数字,您可以执行以下操作。

vector<string> GetVersion(const string &strInput, int iMinSize)
{
    vector<string> vRetValue;

    std::stringstream ss(strInput); 
    string strItem;
    while(std::getline(ss, strItem, '.'))   
        vRetValue.push_back(strItem);

    while(vRetValue.size() < iMinSize)
        vRetValue.push_back("0");

    return vRetValue;
}

int _tmain(int argc, _TCHAR* argv[])
{   
    vector<string> vRetValue = GetVersion("1.0", 3); 
    return 0;
}
于 2012-08-01T13:27:20.820 回答
3

可能会使用std::sscanf(). 它使用简单,并通过相对较少的代码行提供了一定程度的错误检查:

#include <iostream>
#include <string>
#include <cstdio>

int main()
{
    std::string input[] = { "1.0.7", "1.0.", "1.0", "1.", "1" };

    for (size_t i = 0; i < sizeof(input)/sizeof(input[0]); i++)
    {
        std::cout << input[i] << ": ";

        // Init to zero.
        int parts[3] = { 0 };

        // sscanf() returns number of assignments made.
        if (std::sscanf(input[i].c_str(),
                        "%d.%d.%d",
                        &parts[0],
                        &parts[1],
                        &parts[2]) >= 2)
        {
            // OK, the string contained at least two digits.
            std::cout << parts[0]
                      << ","
                      << parts[1]
                      << ","
                      << parts[2]
                      << "\n";
        }
        else
        {
            std::cout << "bad format\n";
        }
    }
    return 0;
}

输出:

1.0.7:1,0,7
1.0.: 1,0,0
1.0: 1,0,0
1.:格式不好
1:格式错误

请参阅在线演示:http: //ideone.com/0Ox9b

于 2012-08-01T13:29:08.840 回答
2

find并且substr是两个非常好的函数重载系列,非常适合许多简单的解析问题,尤其是当您的语法检查只需要松散时。

要从版本向量中提取多个标量,请将找到的索引存储在某处:

const auto a = verstr.find('.');
const std::string major = verstr.substr(0, a);

然后用的重载之一重新使用它string::find,说在之后开始搜索a

const auto b = verstr.find ('.', a+1);
const std::string minor = verstr.substr(a+1, b);

等等。

如果您需要语法检查,请将返回的索引与string::npos

const auto a = verstr.find('.');
if (std::string::npos == a)
    .... bad syntax ....

此答案的 Pastebin 样式版本:

#include <string>
#include <stdexcept>
#include <iostream>

struct Version
{
    std::string Major, Minor, Patch;

    Version(std::string const &Major)
    : Major(Major), Minor("0"), Patch("0")
    {}

    Version(std::string const &Major, std::string const &Minor)
    : Major(Major), Minor(Minor), Patch("0")
    {}

    Version(std::string const &Major, std::string const &Minor, std::string const &Patch)
    : Major(Major), Minor(Minor), Patch(Patch)
    {}
};

std::ostream& operator<< (std::ostream &os, Version const &v)
{
    return os << v.Major << '.' << v.Minor << '.' << v.Patch;
}

Version parse (std::string const &verstr) {
    if (verstr.empty()) throw std::invalid_argument("bad syntax");

    const auto first_dot = verstr.find('.');
    if (first_dot == std::string::npos)
        return Version(verstr);

    const auto second_dot = verstr.find('.', first_dot+1);
    if (second_dot == std::string::npos)
        return Version(verstr.substr(0, first_dot),
                       verstr.substr(first_dot+1, second_dot));


    return Version(verstr.substr(0, first_dot),
                   verstr.substr(first_dot+1, second_dot),
                   verstr.substr(second_dot+1));

}

进而

int main () {
    std::cout << parse("1.0") << '\n'
              << parse("1.0.4+Patches(55,322)") << '\n'
              << parse("1") << '\n';

    parse(""); // expected to throw
}
于 2012-08-01T13:53:17.360 回答
0

尝试这样的事情,而不是行下方的解决方案

string s = "1.0.0";
string delimiters = ".";
size_t current;
size_t next = -1;
do
{
  current = next + 1;
  next = s.find_first_of( delimiters, current );
  string current_substring = s.substr( current, next - current ); // here you have the substring
}
while (next != string::npos);

好的,请不要使用下面的这个解决方案,如果你真的不知道你在做什么,根据下面的讨论这个答案与@DavidSchwartz

看看函数strtok http://www.cplusplus.com/reference/clibrary/cstring/strtok/

  char str[] = "1.0.0";
  char * pch;
  pch = strtok (str,".");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, ".");
  }
于 2012-08-01T13:12:58.053 回答
0

看看 Boost 库,特别是String Algo

对字符串操作的标准库支持在 C++ 中有所限制。重新发明轮子是非常糟糕的。

更新:

我在评论中被问到为什么我认为所有基于 find/substr 的解决方案都是不好的风格。我会尽力的。

由于问题没有另外说明,性能在这里不是问题。可维护性和可读性更为重要。这里提出的所有解决方案都将拆分算法语义与特定版本的解析算法语义紧密联系在一起。这对双方都有害。

这会损害可维护性,因为当您需要更改版本格式时,将涉及更改实现拆分的相同代码块,使其更容易出错。同样适用于单元测试。

这会损害可读性,因为由于语义混合,我无法立即猜测这段代码背后的意图。例如,当我查找解析算法以检查丢失的 3d 版本参数是如何处理的时,我最好不要浪费时间挖掘拆分实现细节。

如果解析模式会稍微困难一些,我会建议使用正则表达式。但是在这种情况下,用分隔符分割字符串是一种通用的操作,通常足以证明将其作为单独的函数是合理的。

于 2012-08-01T13:23:51.367 回答
-1

如果它只是一个小字符串中的简单字符比较......

char[] 不应该那么糟糕......并且 c 函数应该可以工作......(编辑:对于某些人来说,这是一种亵渎......很多 C++ 方法都使用 char* ,无论它是否为 const )。

为什么要使用一个对象,如果它具有相同的功能,使用更多的内存,并且有更多的时间用于进程?

编辑:我看到一些答案假设创建了很多字符串对象......我不知道它是否真的是最好的方法......一个小的 2 行递归 C 函数可以做到这一点而不会喘不过气来。在 c++ 代码中,我可能会使用字符串对象来做到这一点,因为它的喘息可以忽略不计......但只是这么说。

在字符串对象中,我将使用长度属性首先获取最后一个字符(使用 [] 运算符或适当的方法)。然后只需要获取这两个元素(在循环中,或者在接受正则表达式的对象中使用 2 个反向引用(效率较低))

于 2012-08-01T13:32:56.983 回答