1

I have a .ini file and in it i declare Sections like:

[SectionName]

I want to get rid of '[' and ']' to just read in the SectionName, currently i'm using this to achieve what i want:

line.substr(1, line.size() - 2);

But this gets only rid of the first and last Character, no matter what they are. I'm looking for an elegant way to delete the first occurrence of '[' and last occurrence of ']'. Thanks in advance!

EDIT: I tried using this:

void TrimRight(std::string str, std::string chars)
{
    str.erase(str.find_last_not_of(chars) + 1);
}

void TrimLeft(std::string str, std::string chars)
{
    str.erase(0, str.find_first_not_of(chars));
}

TrimLeft(line, "[");
TrimRight(line, "]");

But this is not removing them, for some weird reason...

SupaDupa
  • 161
  • 2
  • 14
  • 2
    What is the expected behaviour if the string is something like `Section[Name]`? Or `[Section]Name`? Or `A[Section]Name`? All contrived examples but they highlight corner cases – Steve Oct 27 '17 at 08:29
  • Possible duplicate of [trim matching characters from start or end of string c++](https://stackoverflow.com/questions/46479513/trim-matching-characters-from-start-or-end-of-string-c) – ilim Oct 27 '17 at 08:29
  • @Steve do you have a way to only delete it if those are on the outside of the string and first and last instance!? – SupaDupa Oct 27 '17 at 08:33
  • @SupaDupa so you want my 3 examples to return `[Name]`, `[Section]` and `[Section]`, respectively? – Steve Oct 27 '17 at 08:34
  • @Steve No, as far as I can understand from the latest comment by SupaDupa , the expected behavior should be to remove only if '[' and ']' are in the beginning and at the end of the string, respectively. – ilim Oct 27 '17 at 08:35
  • Which means that this question is indeed a duplicate. – ilim Oct 27 '17 at 08:35
  • @ilim Not quite, that question is about removing from the start **or** end, not both if some condition is met. – Steve Oct 27 '17 at 08:57
  • @SupaDupa you're not passing a reference to TrimLeft and TrimRight. That is why the passed instance of std::string is passed by value, and the original object instance is not altered. – ilim Oct 27 '17 at 09:00
  • @Steve That is your honest opinion?! Any difference between those two questions could be remedied rather trivially, with some effort and googling by the OP. – ilim Oct 27 '17 at 09:04
  • @ilim Yes, they could, but that doesn't make this question an exact duplicate of that one. That answer is certainly applicable here and it's useful to refer to it. – Steve Oct 27 '17 at 09:05
  • @Steve You yourself pointed out above that the question lacks proper details such as what sort of texts are to be trimmed/handled in the desired manner. I believe OP did not look hard enough for a solution before posting this. If he/she did, then the question I referenced would have come up. OP could then fail to adapt that solution and could ask a separate question, but that is apparently not what happened. Anyhow... In essence, I believe the similarities between the two questions are too much to ignore. – ilim Oct 27 '17 at 09:10

2 Answers2

3

You can utilize the strings front() and back() member functions:

#include <iostream>
#include <string>

int main() {
    std::string s = "[Section]";
    if (s.front() == '[' && s.back() == ']') {
        s.erase(0, 1);
        s.pop_back();
    }
    std::cout << s;
}

or if you want either removed:

if (s.front() == '[') {
    s.erase(0, 1);
}
if (s.back() == ']') {
    s.pop_back();
}

The .pop_back() function removes the last character. Your functions are accepting arguments by value, not reference. Here are the function variations:

A void function where you pass the parameter by reference:

void trimstr(std::string& s) {
    if (s.front() == '[' && s.back() == ']') {
        s.erase(0, 1);
        s.pop_back();
    }
}

and the function that returns a std::string:

std::string gettrimmed(const std::string& s) {
    std::string temp = s;
    if (temp.front() == '[' && temp.back() == ']') {
        temp.erase(0, 1);
        temp.pop_back();
    }
    return temp;
}
Ron
  • 14,674
  • 4
  • 34
  • 47
2

Use string::find_first_of() and string::find_last_of() to find the positions of the two characters. Then get the substring between those two positions:

int main() {
    std::string s("[SectionName]");
    size_t first = s.find_first_of('[');
    size_t last = s.find_last_of(']');
    if (std::string::npos != first && std::string::npos != last)
    {
        std::cout << s.substr(first + 1, last - first - 1);
    }
    return 0;
}

Demo

CinCout
  • 9,486
  • 12
  • 49
  • 67
  • I don't see any reason for downvote just to be consistent string::npos != first && string::npos != last could be std::string::npos != first && std::string::npos != last – Hariom Singh Oct 27 '17 at 08:44
  • I downvoted it because it doesn't match the clarification the OP provided in the comment. – Steve Oct 27 '17 at 08:49
  • Dear OP, comments are no place to modify requirements. Kindly edit your question. – CinCout Oct 27 '17 at 08:53
  • They weren't modified - they were unclear and clarified in the comments – Steve Oct 27 '17 at 08:54
  • 1
    "I'm looking for an elegant way to delete the first occurrence of '[' and last occurrence of ']'." Now he/she is not. – CinCout Oct 27 '17 at 08:56
  • It was phrased poorly but given the context of parsing sections in a .ini file there was a clear ambiguity. – Steve Oct 27 '17 at 08:59