Исключение разделителя строк C

#c #c 11

Вопрос:

Я работаю над фрагментом кода и столкнулся здесь с небольшой проблемой. В целом проблема заключается в разделителе строк и разделении строки C std::.

Строка, которая у меня есть, это:

 std::string nStr = 
R"(
"0000:ae:05.2:
Address: 0000:ae:05.2
Segment: 0x0000
")";
 

Обычно вышеперечисленное намного больше и содержит гораздо больше записей данных.
Разделитель, который я установил, — это»:», так как это будет самый распространенный разделитель, который у меня есть в данных.
То, что я хочу получить, — это 2 строки, т. е. Строка 1 = Адрес и строка 2 = 0000:ae:05.2, но мне также нужно, чтобы 1-я строка обрабатывалась аналогично, поэтому в основном все должно начинаться со строки 1 = заголовок и строки 2 = 0000:ae:05.2

Мой код выглядит так на данный момент:

 int main(int argc, char* argv[])
{
std::string nStr = 
R"(
"0000:ae:05.2:
Address: 0000:ae:05.2
Segment: 0x0000
")";
std::string tLine1="", tLine2="";

//nStr = nStr.erase(nStr.find_last_not_of("nrt"));   

const std::string delimiter = ": ", delim2=":";

std::string::size_type pos = nStr.find(delimiter);
std::string::size_type pos2 = nStr.find(delim2);

if(nStr.npos != pos){
    tLine2 = nStr.substr(pos   1);
    tLine1 = nStr.substr(0, pos);
}
else if(nStr.npos != pos2){
    tLine1 = nStr.substr(0, pos2);
    tLine2 = "blank";
}
else
    std::cout << "Delimiter not specified!n";
 

Что это работает для разделителя «main»,»:», а не для «:». Также он не читает все разделители»:».

Мой вывод будет: tLine1= «0000:ae:05.2: Адрес tLine2= 0000:ae:05.2 Сегмент: 0x0000

Есть какие-нибудь мысли о том, как это можно сделать правильно? Или как подойти к этому лучше? Заранее спасибо.

Комментарии:

1. Я не уверен, какова ваша цель или в чем проблема. Вы ищете первое вхождение «: «и устанавливаете tLine2 для всего после разделителя, а tLine1 для всего перед разделителем. И, похоже, это то, что вы получаете. Возможно ли, что вы хотите сначала разделить строку на разрывы строк и проверить наличие разделителей для каждой строки?

2. Здравствуйте, мне нужно получить следующее: tLine1 = 0000:ae:05.2; tLine2=заголовок; tLine1 = «Адрес»; tLine2=0000:ae:05.2; tLine1 = «Сегмент»; tLine2=0x0000 Я думаю, что пропустил это в описании. Извинения.

Ответ №1:

Приведенный ниже код делает то, что вы хотите сделать.

 #include<iostream>
#include<string>
int main(int argc, char* argv[])
{
    std::string nStr =
        R"(0000:ae:05.2:Address: 0000:ae:05.2 Segment: 0x0000
)";
    std::string tLine1 = "", tLine2 = "";
    const std::string delimiter = ": ";
    size_t pos = 0;
    
    while ((pos = nStr.find(delimiter)) != std::string::npos) {
        tLine1 = nStr.substr(0, pos);
        nStr.erase(0, pos   delimiter.length());
        tLine2 = nStr;
        break;
    }

    std::cout << "tLine1 = " << tLine1<<"n";
    std::cout << "tLine2 = " << tLine2<<"n";
}
 

Выход:

 tLine1 = 0000:ae:05.2:Address
tLine2 = 0000:ae:05.2 Segment: 0x0000
 

Комментарии:

1. Возможно, объяснение того, почему этот код работает, в то время как исходный код не поможет. Или, по крайней мере, объясните, почему символы новой строки в исходной строке создают ошибку.

2. Это здорово. Боюсь, что я дал не самое лучшее описание. Извините. Цель состоит в том, чтобы разделить это следующим образом. tLine1: 0000:ae:05.2, а затем заголовок tLine2: Теперь, как вы можете видеть в моем R»(строка, в которой есть новая строка непосредственно после знака:, не похожая на стандартный разделитель a «: «Теперь все остальные следующие строки будут tLine1: «0000:ae:05.2: и tLine2: «Адрес», разделенный «: »

Ответ №2:

Хорошо, из того, что я могу понять из ваших комментариев, вы хотите разделить исходную строку на строки, а затем разделить отдельные строки, используя «:» в качестве разделителя. За исключением первой строки, которая имеет только одно значение. Таким образом, результирующая пара для этой строки должна иметь значение из строки и строковый литерал «заголовок».

 #include <iostream>
#include <string>
#include <utility>

auto splitLine(const std::stringamp; line) {
    using namespace std::string_literals;

    auto delimiterPos = line.find(": ");
    if (delimiterPos != std::string::npos) {
        return std::make_pair(line.substr(0, delimiterPos),
                              line.substr(delimiterPos   2));
    }
    return std::make_pair(line.substr(1, line.size() - 2), "header"s);
}

int main(int argc, char* argv[]) {
    std::string nStr =
        R"(
"0000:ae:05.2:
Address: 0000:ae:05.2
Segment: 0x0000
")";

    std::size_t newLinePos;
    do {
        newLinePos = nStr.find("n");
        std::string line = nStr.substr(0, newLinePos);
        nStr = nStr.substr(newLinePos   1);

        // To ignore empty lines and the last line that just contains a double quote
        if (line.size() == 0 || line == """) {
            continue;
        }

        auto lines = splitLine(line);
        std::cout << "line1: " << lines.first << "n";
        std::cout << "line2: " << lines.second << "n";
    } while (newLinePos != std::string::npos);
}
 

Я не уверен на 100%, какая часть каждой строки считается первым значением, а какая-вторым. Похоже, вы переключаете это между вопросом и каждым комментарием. Но вы должны быть в состоянии изменить это в соответствии со своим желанием.

Еще один аспект, который я не до конца понял, — это расположение исходной строки. Кажется, он начинается с нового символа строки. И конец новой строкой, за которой следует двойная кавычка. Я должен был поймать именно их.

И первая строка «заголовка» начинается с двойной кавычки и заканчивается двоеточием. Я просто ожидаю, что так будет всегда, и удалил первый и последний символ из указанной строки.

Было бы полезно, если бы у нас был лучший пример для входящих данных.

Комментарии:

1. Это абсолютно идеально. Спасибо.

2. Привет, могу я спросить, почему за заголовком стоит буква «s»? Никогда такого не видел, тбх …

3. В связи с using namespace std::string_literals; тем, что в начале функции она сообщает компилятору, что строковый литерал имеет не тип const char* , а тип std::string . Что гарантирует, что std::make_pair(...) возвращает один и тот же тип для обоих операторов возврата функции. В противном случае компилятор жалуется, что один возвращает a std::pair<std::string, std::string> , а другой возвращает a std::pair<std::string, const char*> .

4. Спасибо за объяснение. Не знал, что тбх.