如何提取字符串中的特定值

How to extract specific values in a string

本文关键字:字符串 何提取 提取      更新时间:2023-10-16

我需要从文件输入中提取存储的字符串中的特定值。它有多个分隔符,我不知道如何从中提取每个特定值。

#include <vector>
#include <string>
#include <sstream>
#include <iostream>    
#include <fstream> 
using namespace std;

string ss = "[4, 90]-3-name";
// i need to extract the values 4, 90, 3 and name 
// the numbers can have multiple digits
stringstream tr(ss);
vector<string> result;
while( tr.good() )
{
string substr;
getline( ss, substr, '-' );
result.push_back( substr );
}
for (int i = 0; i< result.size();i++)
cout << result[i]<< endl;
output:
[4, 90]
3
name

如果您知道所有可能的分隔符,那么您可以用连字符替换 ss 中的每个分隔符,然后上面的代码就可以工作了。请参阅替换功能的链接 http://www.cplusplus.com/reference/string/string/replace/

保罗的回答很聪明,但也许字符串是只读的。这是一个不需要修改字符串的版本

int main()
{
string ss = "[4, 90]-3-name"; // i need to extract the values 4, 90, 3     and name
vector<string> results;
size_t size = ss.size();
size_t first = 0;
size_t i = 0;
while (i < size)
{
char ch = ss[i];
if (ch == '[' || ch == ']' || ch == ' ' || ch == '-' || ch == ',') // delimiter check
{
if (i > first)
results.push_back(ss.substr(first, i - first));
first = i + 1;
}
++i;
}
if (i > first)
results.push_back(ss.substr(first, i - first));
for (auto s : results)
cout << s << 'n';
return 0;
}

希望这是相当清楚的。诀窍是first变量,它跟踪我们期望成为下一个要提取的值的第一个字符(即超出我们刚刚找到的分隔符的字符)的字符的索引。if (i > first)检查只是确保我们不会在结果中添加任何零长度字符串。

现在是C++的方法。这是使用面向对象的习语和现代C++算法。

我们有数据和方法,它们在某种程度上属于一起。为此,C++中有类(结构)。因此,您可以使用成员变量和方法定义一个类,这些类可以使用类变量和方法。一切都作为一个对象工作。

此外。该类知道如何读取或打印其值。只有全班同学应该知道这一点。这种智慧是概括的。

接下来,我们要搜索嵌入在字符串中某处的有趣数据。字符串始终包含某种模式。在您的情况下,您有 3 个整数和一个字符串作为有趣的数据,以及介于两者之间的一些分隔符,无论它们是什么。

为了匹配这些模式并搜索字符串中有趣的部分,C++std::regex.它们非常强大,因此定义起来有点复杂。

在下面的示例中,我将使用const std::regex re(R"((d+).*?(d+).*?(d+).*?([w_]+))");.这定义了 4 组子匹配项(在括号中)以及介于两者之间的内容。所以任何分隔符、空格或任何可能的东西。

如果要更严格,只需更改模式,就可以检测源数据中的错误。请参阅const std::regex re(R"([(d+), (d+)]-(d+)-([w_]+))");。这是一种更严格的方法。如果出现错误,将不会读取输入文件。或者只是以有效数据开头。

请参阅以下示例:

#include <string>
#include <regex>
#include <iterator>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <ios>
#include <iomanip>
std::istringstream testFile{ R"([1, 1]-3-Big_City
[1, 2] - 3 - Big_City
[1, 3] - 3 - Big_City
[2, 1] - 3 - Big_City
[2, 2] - 3 - Big_City
[2, 3] - 3 - Big_City
[2, 7] - 2 - Mid_City
[2, 8] - 2 - Mid_City
[3, 1] - 3 - Big_City
[3, 2] - 3 - Big_City
[3, 3] - 3 - Big_City
[3, 7] - 2 - Mid_City
[3, 8] - 2 - Mid_City
[7, 7] - 1 - Small_City)" };

const std::regex re(R"((d+).*?(d+).*?(d+).*?([w_]+))");

struct CityData
{
// Define the city's data
int xCoordinate{};
int yCoordinate{};
int cityId{};
std::string cityName{};
// Overload the extractor operator >> to read and parse a line
friend std::istream& operator >> (std::istream& is, CityData& cd) {
// We will read the line in this variable
std::string line{};
// Read the line and check, if it is OK
if (std::getline(is, line)) {
// Find the matched substrings
std::smatch sm{};
if (std::regex_search(line, sm, re)) {
// An convert them to students record
cd.xCoordinate = std::stoi(sm[1]);
cd.yCoordinate = std::stoi(sm[2]);
cd.cityId = std::stoi(sm[3]);
cd.cityName = sm[3];
}
else {
is.setstate(std::ios::failbit);
}
}
return is;
}
friend std::ostream& operator << (std::ostream& os, const CityData& cd) {
return os << cd.xCoordinate << ' ' << cd.yCoordinate << ' ' << cd.cityId;
}
};
constexpr int MinimumArrayDimension = 8;
int main()
{
// Define the variable cityData with the vectors range constructor. Read complete input file and parse data
std::vector<CityData> cityData{ std::istream_iterator<CityData>(testFile),std::istream_iterator<CityData>() };
// The following we are doing, because we want to print everything with the correct width
// Read the maximum x coordinate
const int maxRow = std::max(std::max_element (
cityData.begin(), 
cityData.end(), 
[](const CityData & cd1, const CityData & cd2) { return cd1.xCoordinate < cd2.xCoordinate; }
)->xCoordinate, MinimumArrayDimension);
// Read the maximum y coordinate
const unsigned int maxColumn = std::max(std::max_element(
cityData.begin(),
cityData.end(),
[](const CityData & cd1, const CityData & cd2) { return cd1.yCoordinate < cd2.yCoordinate; }
)-> yCoordinate, MinimumArrayDimension);
// Read the maximum city
const unsigned int maxCityID = std::max_element(
cityData.begin(),
cityData.end(),
[](const CityData & cd1, const CityData & cd2) { return cd1.cityId < cd2.cityId; }
)->cityId;
// Get the number of digits that we have here
const int digitSizeForRowNumber = maxRow > 0 ? (int)log10((double)maxRow) + 1 : 1;
const int digitSizeForColumnNumber = std::max(maxColumn > 0 ? (int)log10((double)maxColumn) + 1 : 1,
maxCityID > 0 ? (int)log10((double)maxCityID) + 1 : 1);
// Lambda function for printing the header and the footer
auto printHeaderFooter = [&]() {
std::cout << std::setw(digitSizeForColumnNumber) << "" << " #";
for (int i = 0; i <= (maxColumn+1)* (digitSizeForColumnNumber+1); ++i)
std::cout << '#';
std::cout << "#n";
};

// Print the complete map
std::cout << "nn";
printHeaderFooter();
// Print all rows
for (int row = maxRow; row >= 0; --row) {
// Ptint the row number at the beginning of the line
std::cout << std::setw(digitSizeForColumnNumber) << row << " # ";
// Print all columns
for (int col = 0; col <= maxColumn; ++col)
{
// Find the City ID for the given row (y) and column (x)
std::vector<CityData>::iterator cdi = std::find_if(
cityData.begin(),
cityData.end(),
[row, col](const CityData & cd) { return cd.yCoordinate == row && cd.xCoordinate == col; }
);
// If we could find nothing
if (cdi == cityData.end()) {
// Print empty space
std::cout << std::setw(digitSizeForColumnNumber) << "" << ' ';
}
else {
// Print the CityID
std::cout << std::right << std::setw(digitSizeForColumnNumber) << cdi->cityId << ' ';
}
}
// Print the end of the line
std::cout <<  "#n";
}
printHeaderFooter();
// Print the column numbers
std::cout << std::setw(digitSizeForColumnNumber) << "" << "   ";
for (int col = 0; col <= maxColumn; ++col)
std::cout << std::right << std::setw(digitSizeForColumnNumber) << col << ' ' ;
// And, end
std::cout << "nnn";
return 0;
}

请注意:main读取文件并显示输出。

而且,因为我不能在SO上使用文件,所以我从"std::istringstream"读取数据。这与从文件读取相同。