std::string的工具函数 - 用isspace实现trim函数

本文介绍了如何使用isspace函数改进trim函数,以更好地处理包括Unicode在内的空白字符。通过替换原有的find_first_of方法,采用循环遍历的方式实现了字符串左右两端空白字符的去除。

  在CodeProject上有朋友说我不应该将空白字符限制在" /t/n/r" 以内,应该使用isspace来实现trim函数,以处理Unicode的空白字符。此话在理,所以将trim的三个函数改了一下。(参阅上一篇《std::string的工具函数》)

string  trimLeft( const   string &  str) {
    
string  t  =  str;
    
for  ( string ::iterator i  =  t.begin(); i  !=  t.end(); i ++ ) {
        
if  ( ! isspace( * i)) {
            t.erase(t.begin(), i);
            
break ;
        }
    }
    
return  t;
}

string  trimRight( const   string &  str) {
    
if  (str.begin()  ==  str.end()) {
        
return  str;
    }

    
string  t  =  str;
    
for  ( string ::iterator i  =  t.end()  -   1 ; i  !=  t.begin(); i -- ) {
        
if  ( ! isspace( * i)) {
            t.erase(i 
+   1 , t.end());
            
break ;
        }
    }
    
return  t;
}

string  trim( const   string &  str) {
    
string  t  =  str;

    
string ::iterator i;
    
for  (i  =  t.begin(); i  !=  t.end(); i ++ ) {
        
if  ( ! isspace( * i)) {
            t.erase(t.begin(), i);
            
break ;
        }
    }

    
if  (i  ==  t.end()) {
        
return  t;
    }

    
for  (i  =  t.end()  -   1 ; i  !=  t.begin(); i -- ) {
        
if  ( ! isspace( * i)) {
            t.erase(i 
+   1 , t.end());
            
break ;
        }
    }

    
return  t;
}

  原理很浅显,就是把原来用find_first_of和find_first_not_of实现的查找换成循环,自己用isspace来判断。本来想参考一下boost的实现,不过发现它的代码实在有点复杂,所以还是自己用简单的循环来解决了。

// 价格表管理类 class PriceTableManager { public: static PriceTableManager* GetInstance(); void LoadPriceTable(PriceTableType type, const std::string& filePath, const std::string& sheetName); double GetPrice(PriceTableType type, const std::string& name, const std::string& model, const std::string& brand); double GetAveragePrice(PriceTableType type, const std::string& name, const std::string& model); double CalculateAveragePrice(PriceTableType type, const std::string& name, const std::string& model); private: PriceTableManager(); static PriceTableManager* instance; std::vector<MaterialInfo> steelPriceTable; std::vector<MaterialInfo> standardPriceTable; std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>> steelIndex; std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>> standardIndex; bool steelPriceTableLoaded; bool standardPriceTableLoaded; void BuildIndex(PriceTableType type); void ReadFromExcel(PriceTableType type, XlsBook* xlsBook, const std::string& sheetName); std::string& trim(std::string& s); }; PriceTableManager* PriceTableManager::instance = NULL; PriceTableManager* PriceTableManager::GetInstance() { if (instance == NULL) { instance = new PriceTableManager(); } return instance; } PriceTableManager::PriceTableManager() { steelPriceTableLoaded = false; standardPriceTableLoaded = false; } void PriceTableManager::LoadPriceTable(PriceTableType type, const std::string& filePath, const std::string& sheetName) { if ((type == PRICE_TABLE_STEEL && steelPriceTableLoaded) || (type == PRICE_TABLE_STANDARD && standardPriceTableLoaded)) { return; } printf_str(filePath); XlsBook* xlsBook = new XlsBook(filePath); printf_str("filePath"); ReadFromExcel(type, xlsBook, sheetName); printf_str("filePath"); BuildIndex(type); delete xlsBook; if (type == PRICE_TABLE_STEEL) { steelPriceTableLoaded = true; } else { standardPriceTableLoaded = true; } } void PriceTableManager::ReadFromExcel(PriceTableType type, XlsBook* xlsBook, const std::string& sheetName) { BookSheet* workSheet = xlsBook->getSheet(sheetName.c_str()); std::vector<std::string> brandCol = workSheet->getSheetCol(0); std::vector<std::string> modelCol = workSheet->getSheetCol(1); std::vector<std::string> priceCol = workSheet->getSheetCol(2); std::vector<std::string> nameCol = workSheet->getSheetCol(3); // 不再读取均价列 std::vector<MaterialInfo>* priceTable = (type == PRICE_TABLE_STEEL) ? &steelPriceTable : &standardPriceTable; priceTable->clear(); for (size_t i = 1; i < nameCol.size(); i++) { if (i >= modelCol.size() || i >= brandCol.size() || i >= priceCol.size()) { break; } MaterialInfo info; info.name = trim(nameCol[i]); info.model = trim(modelCol[i]); info.brand = trim(brandCol[i]); info.price = atof(priceCol[i].c_str()); info.avgPrice = 0.0; if (i>100) { break; } priceTable->push_back(info); } } double PriceTableManager::CalculateAveragePrice(PriceTableType type, const std::string& name, const std::string& model) { std::vector& priceTable = (type == PRICE_TABLE_STEEL) ? steelPriceTable : standardPriceTable; double totalPrice = 0.0; int count = 0; // 遍历价格表,计算同名称同型号的平均价格 for (size_t i = 0; i < priceTable.size(); i++) { const MaterialInfo& info = priceTable[i]; if (info.name == name && info.model == model) { totalPrice += info.price; count++; } } if (count > 0) { return totalPrice / count; } return 0.0; } void PriceTableManager::BuildIndex(PriceTableType type) { std::vector& priceTable = (type == PRICE_TABLE_STEEL) ? steelPriceTable : standardPriceTable; std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>>& index =(type == PRICE_TABLE_STEEL) ? steelIndex : standardIndex; index.clear(); for (size_t i = 0; i < priceTable.size(); i++) { const MaterialInfo& info = priceTable[i]; index[info.name][info.model][info.brand] = info; } for (size_t i = 0; i < priceTable.size(); i++) { MaterialInfo& info = priceTable[i]; info.avgPrice = CalculateAveragePrice(type, info.name, info.model); index[info.name][info.model][info.brand].avgPrice = info.avgPrice; } } double PriceTableManager::GetPrice(PriceTableType type, const std::string& name, const std::string& model, const std::string& brand) { std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>>& index = (type == PRICE_TABLE_STEEL) ? steelIndex : standardIndex; std::string n = name; std::string m = model; std::string b = brand; trim(n); trim(m); trim(b); if (index.find(n) != index.end() && index[n].find(m) != index[n].end() && index[n][m].find(b) != index[n][m].end()) { return index[n][m][b].price; } if (index.find(n) != index.end() && index[n].find(m) != index[n].end() && !index[n][m].empty()) { return index[n][m].begin()->second.price; } return 0.0; } double PriceTableManager::GetAveragePrice(PriceTableType type, const string& name, const string& model) { map<string, map<string,map<string, MaterialInfo>>>& index =(type == PRICE_TABLE_STEEL) ? steelIndex : standardIndex; string n = name; string m = model; trim(n); trim(m); if (index.find(n) != index.end() && index[n].find(m) != index[n].end()) { const map<string, MaterialInfo>& brands = index[n][m]; if (brands.empty()) return 0.0; double total = 0.0; int count = 0; for (map<string, MaterialInfo>::const_iterator it = brands.begin(); it != brands.end(); ++it) { total += it->second.price; count++; } return total / count; } return 0.0; } std::string& PriceTableManager::trim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); return s; } 首先数据输入没问题的情况下代码在进行价格查询的时候查询不到现有的价格,请详细读代码并改正
最新发布
09-13
#include <iostream> #include <fstream> #include <sstream> #include <string> #include <regex> struct Record { std::string timestamp; int V = 0, C = 0, L_Pump = 0, R_Pump = 0; }; int safeStoi(const std::string& str) { try { return std::stoi(str); } catch (...) { return 0; } } // 去除字符串前后空格 std::string trim(const std::string& s) { auto start = s.begin(); while (start != s.end() && std::isspace(*start)) ++start; auto end = s.end(); do { --end; } while (std::distance(start, end) > 0 && std::isspace(*end)); return std::string(start, end + 1); } int main() { std::ifstream inputFile("C:\\Users\\A\\Desktop\\input.txt"); std::ofstream outputFile("C:\\Users\\A\\Desktop\\output.csv"); if (!inputFile.is_open()) { std::cerr << "❌ 无法打开输入文件!请检查路径是否正确。" << std::endl; return 1; } if (!outputFile.is_open()) { std::cerr << "❌ 无法创建输出文件!请检查路径是否正确。" << std::endl; return 1; } // 写入CSV表头 outputFile << "Timestamp,V,C,L_Pump,R_Pump\n"; std::string line; std::string currentLine; Record currentRecord; bool inRecord = false; bool hasValidData = false; // 使用 [一-龥] 替代 \u4e00-\u9fa5 避免 regex_error std::regex timestampRegex( R"($$(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})$$[一-龥A-Za-z0-9_:→]+)", std::regex::ECMAScript); while (std::getline(inputFile, line)) { std::smatch match; // 去除前后空格 std::string trim(const std::string & s) { if (s.empty()) return ""; // 首先判断是否为空 auto first = s.begin(); while (first != s.end() && std::isspace(*first)) ++first; if (first == s.end()) return ""; // 全部是空白字符 auto last = s.end(); do { --last; } while (std::isspace(*last) && last != first); return std::string(first, last + 1); } if (trimmed.empty()) continue; // 匹配时间戳 if (std::regex_search(trimmed, match, timestampRegex)) { if (inRecord && hasValidData) { outputFile << currentRecord.timestamp << "," << currentRecord.V << "," << currentRecord.C << "," << currentRecord.L_Pump << "," << currentRecord.R_Pump << "\n"; } currentRecord = Record(); currentRecord.timestamp = match[1]; currentLine = trimmed.substr(match.position() + match.length()); inRecord = true; hasValidData = false; } else if (inRecord) { currentLine += trimmed; } // 检查是否遇到结束标记 if (inRecord && (line.find("errType") != std::string::npos)) { std::istringstream iss(currentLine); std::string token; while (std::getline(iss, token, ',')) { size_t colonPos = token.find(':'); if (colonPos == std::string::npos) continue; std::string key = trim(token.substr(0, colonPos)); std::string valueStr = trim(token.substr(colonPos + 1)); if (key == "V") { currentRecord.V = safeStoi(valueStr); hasValidData = true; } else if (key == "C") { currentRecord.C = safeStoi(valueStr); hasValidData = true; } else if (key == "L_Pump") { currentRecord.L_Pump = safeStoi(valueStr); hasValidData = true; } else if (key == "R_Pump") { currentRecord.R_Pump = safeStoi(valueStr); hasValidData = true; } } if (hasValidData) { outputFile << currentRecord.timestamp << "," << currentRecord.V << "," << currentRecord.C << "," << currentRecord.L_Pump << "," << currentRecord.R_Pump << "\n"; } inRecord = false; currentLine.clear(); } } // 处理结尾可能未保存的记录 if (inRecord && hasValidData) { outputFile << currentRecord.timestamp << "," << currentRecord.V << "," << currentRecord.C << "," << currentRecord.L_Pump << "," << currentRecord.R_Pump << "\n"; } std::cout << "✅ 表格文件已成功生成!共提取到未知数量条记录(需统计)。\n"; inputFile.close(); outputFile.close(); return 0; }
06-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值