c语言字符串定界符,关于c ++:按字符分割字符串

我知道这是一个非常简单的问题,但我只想一次为自己解决

我只想使用字符作为分割定界符将字符串分割成数组。 (很像C#著名的.Split()函数。我当然可以应用蛮力方法,但是我想知道是否有什么更好的方法了。)

到目前为止,我已经搜索过,也许最接近的解决方案是使用strtok(),但是由于不方便(将字符串转换为char数组等),我不喜欢使用它。有没有更简单的方法来实现这一目标?

注意:我想强调这一点,因为人们可能会问:"蛮力为什么不起作用"。我的暴力解决方案是创建一个循环,并在其中使用substr()函数。但是,由于它需要起点和长度,因此在我想分割日期时会失败。因为用户可能输入的时间是2012年7月12日或2011年7月3日,所以在计算" /"定界符的下一个位置之前,我可以真正说出长度。

拆分字符串C ++的可能重复项

使用向量,字符串和stringstream。有点麻烦,但可以解决问题。

std::stringstream test("this_is_a_test_string");

std::string segment;

std::vector<:string> seglist;

while(std::getline(test, segment, '_'))

{

seglist.push_back(segment);

}

导致向量的内容与

std::vector<:string> seglist{"this","is","a","test","string" };

实际上,这种方法正是我所寻找的。很容易理解,不使用外部库,只是非常简单。谢谢@thelazydeveloper!

如果要提高性能,可以添加seglist.reserve(std::count_if(str.begin(), str.end(), [&](char c) { return c == splitChar; }) + (str.empty() ? 1 : 0));如果要拆分的原始字符串存储在str中。

喜欢RegEx的人的另一种方式(C ++ 11 / boost)。就我个人而言,我非常喜欢RegEx这类数据。 IMO比使用分隔符简单地分割字符串要强大得多,因为您可以根据需要选择对构成"有效"数据的内容更加了解。

#include

#include     // copy

#include     // back_inserter

#include        // regex, sregex_token_iterator

#include

int main()

{

std::string str ="08/04/2012";

std::vector<:string> tokens;

std::regex re("\\d+");

//start/end points of tokens in str

std::sregex_token_iterator

begin(str.begin(), str.end(), re),

end;

std::copy(begin, end, std::back_inserter(tokens));

}

因此,您可以在代码中包括整个正则表达式匹配器,仅用于拆分字符串。伤心...

@Dev否,包括一个正则表达式匹配器,以便对构成有效数据的内容更加智能-例如选择数字,并允许使用其他分隔符,例如点或连字符

就二进制大小和整体效率而言,这都是不好的,但是由于这两个原因都不涉及这种情况,因此我不再继续。

@Dev如果一个人对二进制大小有如此极端的约束,那么他们甚至应该重新考虑使用C ++,或者至少使用它的标准库(例如string / vector / etc),因为它们都会产生类似的效果。关于效率,最好的建议来自Donald Knuth-"过早的优化是万恶之源";换句话说,在进行优化之前,首要任务是确定是否存在问题,然后通过诸如剖析之类的客观手段来确定原因,而不是浪费时间试图寻找每一个可能的微观优化。

"在这种情况下,两个人都不关心"-我自己。

@Dev然后我想知道什至提起它们的目的是什么。

我只是不想将整个正则表达式引擎用于查找整数。但是,如果您不想专门化代码,这很好。

Boost具有您要在algorithm/string.hpp中查找的split():

std::string sample ="07/3/2011";

std::vector strs;

boost::split(strs, sample, boost::is_any_of("/"));

另一种可能性是使流具有使用特殊ctype构面的语言环境。流使用ctype构面确定什么是"空白",将其视为分隔符。使用将分隔符分类为空格的ctype构面,读取结果可能非常简单。这是实现方面的一种方法:

struct field_reader: std::ctype {

field_reader(): std::ctype(get_table()) {}

static std::ctype_base::mask const* get_table() {

static std::vector<:ctype_base::mask>

rc(table_size, std::ctype_base::mask());

// we'll assume dates are either a/b/c or a-b-c:

rc['/'] = std::ctype_base::space;

rc['-'] = std::ctype_base::space;

return &rc[0];

}

};

我们通过使用imbue告诉流使用包含它的语言环境,然后从该流中读取数据来使用它:

std::istringstream in("07/3/2011");

in.imbue(std::locale(std::locale(), new field_reader);

设置好后,拆分几乎变得微不足道-只需使用几个istream_iterator初始化向量以从字符串(嵌入在istringstream中)读取片段即可:

std::vector<:string>((std::istream_iterator<:string>(in),

std::istream_iterator<:string>());

显然,如果只在一个地方使用它,则可能会导致过度杀伤。但是,如果您使用过多,则在保持其余代码的整洁度方面可能要走很长的路要走。

我天生不喜欢stringstream,尽管我不确定为什么。今天,我编写了此函数,以允许将std::string通过任意字符或字符串拆分为向量。我知道这个问题很旧,但是我想分享一种拆分std::string的替代方法。

尽管可以很容易地修改它以包括它们,但是该代码完全省略了从结果中分割出的字符串部分。

#include

#include

void split(std::string str, std::string splitBy, std::vector<:string>& tokens)

{

/* Store the original string in the array, so we can loop the rest

* of the algorithm. */

tokens.push_back(str);

// Store the split index in a 'size_t' (unsigned integer) type.

size_t splitAt;

// Store the size of what we're splicing out.

size_t splitLen = splitBy.size();

// Create a string for temporarily storing the fragment we're processing.

std::string frag;

// Loop infinitely - break is internal.

while(true)

{

/* Store the last string in the vector, which is the only logical

* candidate for processing. */

frag = tokens.back();

/* The index where the split is. */

splitAt = frag.find(splitBy);

// If we didn't find a new split point...

if(splitAt == string::npos)

{

// Break the loop and (implicitly) return.

break;

}

/* Put everything from the left side of the split where the string

* being processed used to be. */

tokens.back() = frag.substr(0, splitAt);

/* Push everything from the right side of the split to the next empty

* index in the vector. */

tokens.push_back(frag.substr(splitAt+splitLen, frag.size()-(splitAt+splitLen)));

}

}

要使用,只需像这样致电...

std::string foo ="This is some string I want to split by spaces.";

std::vector<:string> results;

split(foo,"", results);

现在,您可以随意访问向量中的所有结果。就这么简单-没有stringstream,没有第三方库,没有回到C!

您对为什么会更好会有任何争议?

看看boost :: tokenizer

如果您想汇总自己的方法,则可以使用std::string::find()确定拆分点。

感谢您的字符串查找提示。永远喜欢听到std解决方案!

erase()函数呢?如果您知道要在字符串中拆分的位置,则可以使用erase()"提取"字符串中的字段。

std::string date("01/02/2019");

std::string day(date);

std::string month(date);

std::string year(date);

day.erase(2, string::npos); //"01"

month.erase(0, 3).erase(2); //"02"

year.erase(0,6); //"2019"

您是否有理由不想将string转换为字符数组(char*)?调用.c_str()相当容易。您还可以使用循环和.find()函数。

弦类

字符串.find()

字符串.c_str()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值