简体   繁体   English

在C ++中从头到尾将字符串分成两个一组

[英]Splitting up a string from end to start into groups of two in C++

I was curious about the way I could make a program, that takes a string, then detects the end of it, and then starts splitting it up "from end toward the start", into the groups of two? 我很好奇我制作程序的方式,该程序接受一个字符串,然后检测它的结尾,然后开始将它“从结尾到开头”分成两部分? For instance, the user enters mskkllkkk and the output has to be m sk kl lk kk . 例如,用户输入mskkllkkk ,并且输出必须为m sk kl lk kk

I tried to search the net for the tools I needed, and got familiar with iterators, and tried to use them for this purpose. 我尝试在网上搜索所需的工具,并熟悉了迭代器,并尝试将其用于此目的。 I did something like this: 我做了这样的事情:

#include "iostream"
#include "string"
#include "conio.h"

int main() {
    int k=0,i=-1;
    std::string str1;
    std::string::iterator PlaceCounter;
    std::cin >> str1;
    PlaceCounter = str1.end();
    for (PlaceCounter; PlaceCounter != str1.begin(); --PlaceCounter)
    {
        ++k;
        if (k % 2 == 0 && k-1 != 0) {
            ++i;
            str1.insert(str1.end()-k-i,' ');
        }
    }
    std::cout << str1;
    _getch();
return 0;
}

At first, it seemed to be working just fine when I entered a couple of arbitrary cases(Such thing can exactly be used in calculators to make the numbers more readable by putting each three digits in one group, from the end toward the start), But suddenly when I entered this: jsfksdjfksdjfkdsjfskjdfkjsfn , I got the error message:" String iterator not decrementable ". 起初,当我输入几个任意情况时,它似乎工作得很好(可以将计算器中的所有三个数字从头到尾全部放入一组,从而使数字更易读,这样的事情可以准确地用在计算器中),但是突然我输入以下内容: jsfksdjfksdjfkdsjfskjdfkjsfn ,我得到了错误消息:“ 字符串迭代器不可减少 ”。

Presumably I need to study much more pages of my book for C++ to be able to solve this myself, but for now I'm just being super-curious as a beginner. 大概我需要为C ++学习更多的书,以便自己解决这个问题,但是现在我还是一个初学者,对此非常好奇。 Why is that error message? 为什么显示该错误信息? Thanks in advance. 提前致谢。

When you insert() into your string the iterators to it may get invalidated. 当您在字符串中insert() ,对其的迭代器可能会失效。 In particular all iterators past the insertion point should be considered invalidated in all cases but also all iterators get invalidated if the std::string needs to get more memory: the internal buffer will be replaced by a bigger one, causing all existing iterator (and references and pointers) to string elements to be invalidated. 特别是在所有情况下,插入点之后的所有迭代器在所有情况下均应视为无效,但如果std::string需要获得更多内存,则所有迭代器也会无效:内部缓冲区将被更大的缓冲区替换,从而导致所有现有的迭代器(以及引用和指针)指向要无效的字符串元素。

The easiest fix to the problem is to make sure that the string doesn't need to allocate more memory by reserve() ing enough space ahead of time. 解决该问题的最简单方法是,通过reserve()提前分配足够的空间来确保该字符串不需要分配更多的内存。 Since you add one space for every two characters, making sure that there is space for str1.size() + str1.size() / 2u characters should be sufficient: 由于您每两个字符添加一个空格,因此请确保有足够的空间来str1.size() + str1.size() / 2u字符:

str1.reserve(str1.size() + str1.size() / 2u);
for (auto PlaceCounter = str1.end(); PlaceCounter != str1.begin(); --PlaceCounter) {
    // ...
}

Note that your algorithm is rather inefficient: it is an O(n 2 ). 请注意,您的算法效率很低:它是O(n 2 )。 The operation can be done with O(n) complexity instead. 该操作可以用O(n)复杂度来完成。 You'd resize the string to the appropriate size right from the start, filling the tail with some default characters and then copy the content moving from the end directly to the appropriate location. 您将从一开始就将字符串的大小调整为适当的大小,在尾部填充一些默认字符,然后将内容从末尾直接复制到适当的位置。

str1.insert(str1.end()-k-i,' ');

This modifies the string the loop is iterating over. 这将修改循环迭代的字符串。 Specifically, this inserts something into the string. 具体来说,这会在字符串中插入一些内容。

With a std::string , much like a std::vector , insertion into a string will (may) invalidate all existing iterators pointing to the string. 使用std::string ,非常类似于std::vector ,将其插入字符串将(可能)使所有指向该字符串的现有迭代器无效。 The first insertion performed by the shown code results in undefined behavior, as soon as the existing, now invalidated, iterators are referenced afterwards. 所显示的代码执行的第一次插入会导致未定义的行为,随后将引用现有的,现已失效的迭代器。

You will need to either replace your iterators with indexes into the string, or instead of modifying the existing string construct a new string, leaving the original string untouched. 您将需要用字符串中的索引替换迭代器,或者代替修改现有字符串以构造新字符串,而保持原始字符串不变。

Here is a possible C++ approach to try. 这是一种可能的C ++方法。 From my tool bag, here is how I insert commas into a decimal string (ie s is expected to contain digits): 从我的工具包中,这是我如何将逗号插入十进制字符串(即s应该包含数字):

Input: "123456789" 输入:“ 123456789”

// insert comma's from right (at implied decimal point) to left
std::string digiCommaL(std::string s)
{
   // Note: decrementing a uint (such as size_t) will loop-around, 
   //       and not underflow.  Be sure to use int ...

   int32_t sSize = static_cast<int32_t>(s.size()); // change to int
   //      ^^^^^-----------_____
   if (sSize > 3)          vvvvv
      for (int32_t indx = (sSize - 3); indx > 0; indx -= 3)
         s.insert(static_cast<size_t>(indx), 1, ',');

   return(s);
} 

Returns: "123,456,789" 返回:“ 123,456,789”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM