如何提取字符串中的特定值
Posted
技术标签:
【中文标题】如何提取字符串中的特定值【英文标题】:How to extract specific values in a string 【发布时间】:2019-07-27 08:41:38 【问题描述】:我需要从文件输入中提取存储的字符串中的特定值。它有多个分隔符,我不知道如何从中提取每个特定值。
#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
【问题讨论】:
可能重复? SO: How to extract specific elements from a string?(猜猜我是怎么找到这个的...);-) C++ 有一个非常好的<regex>
库。
@Yksisarvinen 这是见仁见智的问题。我会这样描述它的不足。
好吧,我的字符串有更多不同的分隔符。
你对输入格式了解多少?
【参考方案1】:
如果您知道所有可能的分隔符,那么您可以将 ss 中的每个分隔符替换为连字符,然后您的上述代码就可以工作了。请参阅替换功能的链接 http://www.cplusplus.com/reference/string/string/replace/
【讨论】:
【参考方案2】:Paul 的回答很聪明,但字符串可能是只读的。这是一个不需要修改字符串的版本
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)
检查只是确保我们不会在结果中添加任何零长度字符串。
【讨论】:
【参考方案3】:现在是 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 << "\n\n";
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 << "\n\n\n";
return 0;
请注意:main
读取文件并显示输出。
而且,因为我不能在 SO 上使用文件,所以我从“std::istringstream”读取数据。这和从文件中读取是一样的。
【讨论】:
以上是关于如何提取字符串中的特定值的主要内容,如果未能解决你的问题,请参考以下文章