String和stdio支持 #2

Merged
ArchZer0 merged 5 commits from archzero_dev into main 2026-08-16 16:57:13 +08:00
4 changed files with 568 additions and 1 deletions
Showing only changes of commit 1f8fa26d73 - Show all commits
+7 -1
View File
@@ -5,7 +5,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# 定义源文件 # 定义源文件
set(BETTERSTL_SOURCES set(BETTERSTL_SOURCES
src/big_integer.cpp src/big_integer.cpp
src/big_decimal.cpp) src/big_decimal.cpp
src/string.cpp)
# 生成静态库 (.a 文件) # 生成静态库 (.a 文件)
add_library(BetterSTL_static STATIC ${BETTERSTL_SOURCES}) add_library(BetterSTL_static STATIC ${BETTERSTL_SOURCES})
@@ -36,6 +37,11 @@ target_include_directories(BigDecimalTests PRIVATE include)
target_link_libraries(BigDecimalTests PRIVATE BetterSTL_static) target_link_libraries(BigDecimalTests PRIVATE BetterSTL_static)
add_test(NAME BigDecimalTests COMMAND BigDecimalTests) add_test(NAME BigDecimalTests COMMAND BigDecimalTests)
add_executable(StringTests tests/StringTest.cpp)
target_include_directories(StringTests PRIVATE include)
target_link_libraries(StringTests PRIVATE BetterSTL_static)
add_test(NAME StringTests COMMAND StringTests)
# 生成导出信息用于外部使用 # 生成导出信息用于外部使用
install(TARGETS BetterSTL_static BetterSTL_shared install(TARGETS BetterSTL_static BetterSTL_shared
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
+92
View File
@@ -0,0 +1,92 @@
#pragma once
#include <string>
#include <vector>
#include <algorithm>
#include <cctype>
namespace bstl {
class String {
public:
String();
String(const std::string& str);
String(const char* str);
String(const String& other) = default;
String& operator=(const String& other) = default;
// 获取标准字符串
std::string str() const;
const char* c_str() const;
size_t length() const;
size_t size() const;
bool empty() const;
// 获取/修改字符
char at(size_t pos) const;
char operator[](size_t pos) const;
char& operator[](size_t pos);
// 分割 - 按分隔符分割字符串
std::vector<String> split(const String& delimiter = " ") const;
// 连接 - 用分隔符连接多个字符串
static String join(const std::vector<String>& parts, const String& delimiter = "");
// 替换 - 替换第一个/所有匹配项
String replace(const String& oldStr, const String& newStr, int count = -1) const;
// 大小写转换
String upper() const;
String lower() const;
String capitalize() const; // 首字母大写
String title() const; // 每个单词首字母大写
// 判断函数
bool startswith(const String& prefix) const;
bool endswith(const String& suffix) const;
bool contains(const String& substring) const;
bool isdigit() const;
bool isalpha() const;
bool isalnum() const;
bool isspace() const;
bool isupper() const;
bool islower() const;
// 查找和计数
int find(const String& substring, size_t start = 0) const;
int rfind(const String& substring) const; // 从后往前查找
int count(const String& substring) const;
// 去除空格和其他字符
String strip() const; // 去除前后空格
String lstrip() const; // 去除前导空格
String rstrip() const; // 去除尾部空格
String strip(const String& chars) const; // 去除指定字符
// 对齐和填充
String ljust(size_t width, char fillchar = ' ') const;
String rjust(size_t width, char fillchar = ' ') const;
String center(size_t width, char fillchar = ' ') const;
// 字符串转换
int toInt() const;
long long toLongLong() const;
double toDouble() const;
// 运算符重载
String operator+(const String& other) const;
String operator+(const char* str) const;
String& operator+=(const String& other);
bool operator==(const String& other) const;
bool operator!=(const String& other) const;
bool operator<(const String& other) const;
bool operator>(const String& other) const;
bool operator<=(const String& other) const;
bool operator>=(const String& other) const;
private:
std::string data_;
};
} // namespace bstl
+362
View File
@@ -0,0 +1,362 @@
#include "bstl/string.hpp"
#include <sstream>
#include <stdexcept>
namespace bstl {
String::String() : data_("") {}
String::String(const std::string& str) : data_(str) {}
String::String(const char* str) : data_(str == nullptr ? "" : str) {}
std::string String::str() const {
return data_;
}
const char* String::c_str() const {
return data_.c_str();
}
size_t String::length() const {
return data_.length();
}
size_t String::size() const {
return data_.size();
}
bool String::empty() const {
return data_.empty();
}
char String::at(size_t pos) const {
if (pos >= data_.size()) {
throw std::out_of_range("String::at: index out of range");
}
return data_[pos];
}
char String::operator[](size_t pos) const {
return data_[pos];
}
char& String::operator[](size_t pos) {
return data_[pos];
}
std::vector<String> String::split(const String& delimiter) const {
std::vector<String> result;
if (data_.empty()) {
return result;
}
if (delimiter.empty()) {
result.push_back(*this);
return result;
}
size_t start = 0;
size_t pos = 0;
while ((pos = data_.find(delimiter.data_, start)) != std::string::npos) {
result.push_back(String(data_.substr(start, pos - start)));
start = pos + delimiter.size();
}
result.push_back(String(data_.substr(start)));
return result;
}
String String::join(const std::vector<String>& parts, const String& delimiter) {
if (parts.empty()) {
return String("");
}
std::string result = parts[0].str();
for (size_t i = 1; i < parts.size(); i++) {
result += delimiter.str() + parts[i].str();
}
return String(result);
}
String String::replace(const String& oldStr, const String& newStr, int count) const {
if (oldStr.empty()) {
return *this;
}
std::string result = data_;
size_t pos = 0;
int replaced = 0;
while ((pos = result.find(oldStr.data_, pos)) != std::string::npos && (count < 0 || replaced < count)) {
result.replace(pos, oldStr.size(), newStr.str());
pos += newStr.size();
replaced++;
}
return String(result);
}
String String::upper() const {
std::string result = data_;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::toupper(c); });
return String(result);
}
String String::lower() const {
std::string result = data_;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::tolower(c); });
return String(result);
}
String String::capitalize() const {
if (data_.empty()) {
return *this;
}
std::string result = data_;
result[0] = std::toupper(static_cast<unsigned char>(result[0]));
for (size_t i = 1; i < result.size(); i++) {
result[i] = std::tolower(static_cast<unsigned char>(result[i]));
}
return String(result);
}
String String::title() const {
std::string result = data_;
bool newWord = true;
for (size_t i = 0; i < result.size(); i++) {
if (std::isspace(static_cast<unsigned char>(result[i]))) {
newWord = true;
} else {
if (newWord) {
result[i] = std::toupper(static_cast<unsigned char>(result[i]));
newWord = false;
} else {
result[i] = std::tolower(static_cast<unsigned char>(result[i]));
}
}
}
return String(result);
}
bool String::startswith(const String& prefix) const {
if (prefix.size() > data_.size()) {
return false;
}
return data_.compare(0, prefix.size(), prefix.data_) == 0;
}
bool String::endswith(const String& suffix) const {
if (suffix.size() > data_.size()) {
return false;
}
return data_.compare(data_.size() - suffix.size(), suffix.size(), suffix.data_) == 0;
}
bool String::contains(const String& substring) const {
return data_.find(substring.data_) != std::string::npos;
}
bool String::isdigit() const {
if (data_.empty()) return false;
for (unsigned char c : data_) {
if (!std::isdigit(c)) return false;
}
return true;
}
bool String::isalpha() const {
if (data_.empty()) return false;
for (unsigned char c : data_) {
if (!std::isalpha(c)) return false;
}
return true;
}
bool String::isalnum() const {
if (data_.empty()) return false;
for (unsigned char c : data_) {
if (!std::isalnum(c)) return false;
}
return true;
}
bool String::isspace() const {
if (data_.empty()) return false;
for (unsigned char c : data_) {
if (!std::isspace(c)) return false;
}
return true;
}
bool String::isupper() const {
if (data_.empty()) return false;
for (unsigned char c : data_) {
if (std::isalpha(c) && !std::isupper(c)) {
return false;
}
}
return true;
}
bool String::islower() const {
if (data_.empty()) return false;
for (unsigned char c : data_) {
if (std::isalpha(c) && !std::islower(c)) {
return false;
}
}
return true;
}
int String::find(const String& substring, size_t start) const {
size_t pos = data_.find(substring.data_, start);
return pos == std::string::npos ? -1 : static_cast<int>(pos);
}
int String::rfind(const String& substring) const {
size_t pos = data_.rfind(substring.data_);
return pos == std::string::npos ? -1 : static_cast<int>(pos);
}
int String::count(const String& substring) const {
if (substring.empty()) return 0;
int count = 0;
size_t pos = 0;
while ((pos = data_.find(substring.data_, pos)) != std::string::npos) {
count++;
pos += substring.size();
}
return count;
}
String String::strip() const {
size_t start = 0;
size_t end = data_.size();
while (start < end && std::isspace(static_cast<unsigned char>(data_[start]))) {
start++;
}
while (end > start && std::isspace(static_cast<unsigned char>(data_[end - 1]))) {
end--;
}
return String(data_.substr(start, end - start));
}
String String::lstrip() const {
size_t start = 0;
while (start < data_.size() && std::isspace(static_cast<unsigned char>(data_[start]))) {
start++;
}
return String(data_.substr(start));
}
String String::rstrip() const {
size_t end = data_.size();
while (end > 0 && std::isspace(static_cast<unsigned char>(data_[end - 1]))) {
end--;
}
return String(data_.substr(0, end));
}
String String::strip(const String& chars) const {
size_t start = 0;
size_t end = data_.size();
while (start < end && chars.data_.find(data_[start]) != std::string::npos) {
start++;
}
while (end > start && chars.data_.find(data_[end - 1]) != std::string::npos) {
end--;
}
return String(data_.substr(start, end - start));
}
String String::ljust(size_t width, char fillchar) const {
if (data_.size() >= width) {
return *this;
}
std::string result = data_;
result.append(width - data_.size(), fillchar);
return String(result);
}
String String::rjust(size_t width, char fillchar) const {
if (data_.size() >= width) {
return *this;
}
std::string result(width - data_.size(), fillchar);
result.append(data_);
return String(result);
}
String String::center(size_t width, char fillchar) const {
if (data_.size() >= width) {
return *this;
}
size_t totalPad = width - data_.size();
size_t leftPad = totalPad / 2;
size_t rightPad = totalPad - leftPad;
std::string result(leftPad, fillchar);
result.append(data_);
result.append(rightPad, fillchar);
return String(result);
}
int String::toInt() const {
return std::stoi(data_);
}
long long String::toLongLong() const {
return std::stoll(data_);
}
double String::toDouble() const {
return std::stod(data_);
}
String String::operator+(const String& other) const {
return String(data_ + other.data_);
}
String String::operator+(const char* str) const {
return String(data_ + (str == nullptr ? "" : str));
}
String& String::operator+=(const String& other) {
data_ += other.data_;
return *this;
}
bool String::operator==(const String& other) const {
return data_ == other.data_;
}
bool String::operator!=(const String& other) const {
return data_ != other.data_;
}
bool String::operator<(const String& other) const {
return data_ < other.data_;
}
bool String::operator>(const String& other) const {
return data_ > other.data_;
}
bool String::operator<=(const String& other) const {
return data_ <= other.data_;
}
bool String::operator>=(const String& other) const {
return data_ >= other.data_;
}
} // namespace bstl
+107
View File
@@ -0,0 +1,107 @@
#include <bstl/string.hpp>
#include <cassert>
#include <iostream>
int main() {
using bstl::String;
// 基本构造和获取
String s1("Hello, World!");
assert(s1.length() == 13);
assert(s1.c_str() == std::string("Hello, World!"));
// split 分割
String s2("apple,banana,cherry");
auto parts = s2.split(",");
assert(parts.size() == 3);
assert(parts[0] == String("apple"));
assert(parts[1] == String("banana"));
assert(parts[2] == String("cherry"));
// join 连接
std::vector<String> words = {String("Hello"), String("World")};
String joined = String::join(words, " ");
assert(joined == String("Hello World"));
// replace 替换
String s3("hello hello world");
String replaced = s3.replace("hello", "hi");
assert(replaced == String("hi hi world"));
String replaced1 = s3.replace("hello", "hi", 1);
assert(replaced1 == String("hi hello world"));
// upper/lower
String s4("HeLLo WoRLd");
assert(s4.upper() == String("HELLO WORLD"));
assert(s4.lower() == String("hello world"));
// capitalize
String s5("hello");
assert(s5.capitalize() == String("Hello"));
// title
String s6("hello world");
assert(s6.title() == String("Hello World"));
// startswith/endswith
String s7("hello.txt");
assert(s7.startswith("hello"));
assert(s7.endswith(".txt"));
assert(!s7.startswith(".txt"));
// contains
assert(s7.contains("llo"));
assert(!s7.contains("xyz"));
// isdigit/isalpha/isalnum
assert(String("12345").isdigit());
assert(!String("123a").isdigit());
assert(String("abc").isalpha());
assert(!String("abc1").isalpha());
assert(String("abc123").isalnum());
// isupper/islower
assert(String("HELLO").isupper());
assert(String("hello").islower());
assert(!String("Hello").isupper());
// find/rfind/count
assert(s2.find("banana") == 6);
assert(s2.find("xyz") == -1);
assert(s3.count("hello") == 2);
// strip
String s8(" hello world ");
assert(s8.strip() == String("hello world"));
assert(s8.lstrip() == String("hello world "));
assert(s8.rstrip() == String(" hello world"));
// ljust/rjust/center
String s9("hi");
assert(s9.ljust(5, '.') == String("hi..."));
assert(s9.rjust(5, '.') == String("...hi"));
assert(s9.center(5, '.') == String(".hi.."));
// 字符串转换
assert(String("123").toInt() == 123);
assert(String("456789").toLongLong() == 456789);
assert(String("3.14").toDouble() == 3.14);
// 运算符
String sa("Hello");
String sb(" World");
String sc = sa + sb;
assert(sc == String("Hello World"));
sa += sb;
assert(sa == String("Hello World"));
// 比较
assert(String("abc") < String("def"));
assert(String("xyz") > String("abc"));
std::cout << "All String tests passed!\n";
return 0;
}