将整数从字符串保存到向量

Save integers from string to vector

我需要将整数从字符串保存到向量。

数字的定义:每一个完全由数字组成的字符串子串,在该子串的第一个字符前有一个space,在最后一个字符后有一个space或标点符号,除非substring 位于字符串的开头或结尾(在这种情况下,前面不必有 space 或后面有 space 或标点符号)。

EXAMPLE 1: "120 brave students, 35 failed, remaining 85..." Numbers: 120, 35, 85

EXAMPLE 2: "2PAC and U2 have class" Numbers: // there aren't any numbers

#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
int CharToInt(int c) {
  return abs('0' - c);
}
int MakeNumber(std::vector < int > temp) {
  int num;
  if (temp.size() == 1)
    num = temp[0];
  if (temp.size() == 2)
    num = temp[0] * 10 + temp[1];
  if (temp.size() == 3)
    num = temp[0] * 100 + temp[1] * 10 + temp[2];
  if (temp.size() == 4)
    num = temp[0] * 1000 + temp[1] * 100 + temp[2] * 10 + temp[3];
  return num;
}

std::vector < int > ExtractNumbers(std::string str) {
  std::vector < int > a;
  bool found_number;
  std::vector < int > temp;
  for (int i = 0; i < str.length(); i++) {
    // skip spaces
    found_number = false;
    while (str[i] == ' ' && i < str.length())
      i++;
    // inside word
    while (str[i] != ' ' && i < str.length()) {
      while (str[i] >= '0' && str[i] <= '9' && i < str.length()) {
        temp.push_back(CharToInt(str[i]));
        i++;
        found_number = true;
      }
      i++;
    }
    if (found_number)
      a.push_back(MakeNumber(temp));
    temp.clear();
  }
  return a;
}

int main() {
  std::vector < int > a = ExtractNumbers("120 brave students, 35 failed, remaining 85...");
  std::vector < int > b = ExtractNumbers("2PAC and U2 have class");
  for (int i: a) std::cout << i << " ";
  std::cout << std::endl;
  for (int i: b) std::cout << i << " ";
  return 0;
}

OUTPUT:

120 35 85 // ✅

2 2 // ❌

你能帮我修改一下以使其在示例 2 中正常工作吗? 怎么查看号码前有space,号码后有space/punctuation?

makeNumber 应该是

int MakeNumber(std::vector <int> temp) {
    int num = 0;
    for( int digit : temp){
        num *= 10;
        num += digit;
    }
    return num;
}

不会更改答案,但可以处理任意数量的数字(假设它适合 int)

你的要求,数字后面可以有标点符号,但不能有其他字符,所以它们被认为是一个数字,这使得问题有点难。

解决此“解析规则”的一种方法是使用正则表达式。 首先,我们将输入字符串拆分为单词(由空格包围),然后 我们测试一个单词是否满足数量要求。

我们使用 std::istringstream 从字符串中一次读取一个单词,而不是回退到细节 C-style 基于字符的解析代码。

最后,无论我们考虑什么数字,我们都用 std::stoi() 进行转换。

#include <iostream>
#include <sstream>
#include <algorithm>
#include <string>
#include <vector>
#include <cctype>
#include <regex>

using StringVector = std::vector<std::string>;
using I32Vector = std::vector<int32_t>;

static std::regex number_regex(R"(\d+[\.\,\:\;\!\?]*)");

inline bool is_number(const std::string& s) {
  std::cmatch m;
  return std::regex_match(s.c_str(),m,number_regex);
}

I32Vector extract_numbers(const std::string& s) {
  I32Vector result;
  std::string word;
  std::istringstream is{s};
  while (!is.eof()) {
    is >> word;
    std::cout << "[" << word << "]";
    if (is_number(word)) {
      std::cout << " is a number.";
      std::cout.flush();
      result.push_back(std::stoi(word));
    }
    std::cout << std::endl;
  }
  return result;
}

std::ostream& operator<<(std::ostream& stream,
             const I32Vector& v) {
  if (v.empty())
    stream << "()" << std::endl;
  else {
    stream << "(" << v[0];
    for (size_t i = 1; i < v.size(); i++) {
      stream << " " << v[i];
    }
    stream << ")" << std::endl;
  }
  return stream;
}

int main (int argc, const char* argv[]) {
  StringVector test_strings{
    "120 brave students, 35 failed, remaining 85...",
    "2PAC and U2 have class",
    "120 brave students, 35 failed,2 remaining 85..."
  };

  for (const auto& s : test_strings) {
    I32Vector numbers = extract_numbers(s);
    std::cout << s << " => " << numbers << std::endl;
  }
  
  return 0;
}

编译后产生,例如clang++-13 -std=c++20 -o numbers numbers.cpp:

120 brave students, 35 failed, remaining 85... => (120 35 85)
2PAC and U2 have class => ()

我找到了解决这个问题的方法。

#include <iostream>
#include <string>
#include <vector>
std::vector < int > extract_numbers(std::string s) {
  std::vector < int > vek;
  for (int i = 0; i < s.length(); i++) {
    std::string word;
    while (s[i] == ' ' && i < s.length()) i++;
    while (s[i] != ' ' && i < s.length()) word += s[i++];
    int j = 0;
    while (word[j] >= '0' && word[j] <= '9') j++;
    std::string spaces = ".,;!?";
    for (int i = 0; i < spaces.size(); i++)
      if (word[j] == spaces[i] || word[j] == '[=10=]') {
        vek.push_back(std::stoi(word));
        break;
      }
  }
  return vek;
}
int main() {
  std::string s;
  std::getline(std::cin, s);
  for (int i: extract_numbers(s))
    std::cout << i << " ";
  return 0;
}