Как разбить эти строки на массив - PullRequest
2 голосов
/ 30 ноября 2010

Я ищу способ разбить следующую строку текста на массив.

Вот некоторый текст \ r \ n "здесь другая строка" \ r \nИ еще одна строка

Так что результирующий массив будет иметь вид:

Вот текст

\ r \ n

"

вот еще одна строка

"

\ r \ n

И еще одна строка

Обратите внимание, что здесь по существу два разделителя, " и \ r \ n .
Мне нужно сделать это в C ++, и в будущем могут появиться дополнительные разделители.
Есть идеи?

Спасибо зааванс.

Редактировать: Нет, это не домашняя работа.

Вот что у меня есть:

const RWCString crLF = "\r\n";
const RWCString doubleQuote = "\"";


    RWTValOrderedVector<RWCString> Split(const RWCString &value, const RWCString &specialContent)
    {
        RWTValOrderedVector<RWCString> result;

        unsigned index = 0;

        RWCString str = value;

        while ( ( index = str.index( specialContent, 0, RWCString::ignoreCase ) ) != RW_NPOS )
        {
            RWCString line = str(0, index);

            result.append(line);
            result.append(specialContent);

            str = str(index, str.length() - index);
            str = str(specialContent.length(), str.length() - specialContent.length());
        }

        if (str.length() > 0)
        {
            result.append(str);
        }

        return result;
    }

        void replaceSpecialContents(const RWCString &value)
        {

            RWTValOrderedVector<RWCString> allStrings;

            RWTValOrderedVector<RWCString> crLFStrings = Split(value, crLF);

            for (unsigned i=0; i<crLFStrings.entries(); i++)
            {
            RWTValOrderedVector<RWCString> dqStrings = Split(crLFStrings[i], doubleQuote);

                if (dqStrings.entries() == 1)
                {
                    allStrings.append(crLFStrings[i]);
                }
                else
                {
                    for (unsigned j=0; j<dqStrings.entries(); j++)
                    {
                        allStrings.append(dqStrings[j]);
                    }
                }
            }

    }

Ответы [ 8 ]

2 голосов
/ 30 ноября 2010

Вот способ сделать это, который будет работать в C и C ++:

//String to tokenize:
char str[] = "let's get some tokens!";

//A set of delimiters:
char delims[] = " ";

//List of tokens:
char *tok1 = NULL,
     *tok2 = NULL,
     *tok3 = NULL;

//Tokenize the string:
tok1 = strtok(str, delims);
tok2 = strtok(NULL, delims); //after you get the first token
tok3 = strtok(NULL, delims); //supply "NULL" as first strtok parameter

Вы можете изменить это различными способами.Вы можете поместить все вызовы "strtok (NULL, delims)" в цикл, чтобы сделать его более гибким, вы можете взаимодействовать со строкой C ++ с помощью .c_str () и т. Д.

1 голос
/ 03 декабря 2011

Основываясь на используемом вами API Rogue Wave SourcePro, вы можете использовать RWTRegex для разбиения строки на токены:

RWTValOrderedVector<RWCString> tokenize(const RWCString& str)
{
    RWTRegex<char> re("\\r\\n|\"|([^\"\\r]|\\r[^\\n])*|\\r$");

    RWTRegex<char>::iterator it(re, str);

    RWTValOrderedVector<RWCString> result;
    for (; it != RWTRegex<char>::iterator(); ++it) {
        result.append(it->subString(str));
    }
    return result;
}

Подробнее о RWTRegex см. http://www.roguewave.com/Portals/0/products/sourcepro/docs/12.0/html/sourceproref/classRWTRegex.html.

1 голос
/ 01 декабря 2010

Действительно простой способ - просто использовать flex:
Вы можете создать действительно простой лексер для приложения C ++ в несколько строк, которые будут очень удобочитаемыми.

Примечание:

Я бы отметил, что вы должны быть осторожны с '\ r \ n'. Если вы откроете файл в текстовом режиме (по умолчанию), то стандартное чтение потока преобразует стандартную последовательность завершения строки в '\ n'. На некоторых платформах последовательность завершения строки заканчивается на «\ r \ n», поэтому, если вы читаете поток из файла, вы можете увидеть только символ «\ n».

split.lex

%option c++
%option noyywrap
%%
\"           return 1;
\r\n         return 2;
[^"\r\n]*    return 3;
%%

main.cpp

#include "FlexLexer.h"

int main()
{
    yyFlexLexer     lexer(&std::cin, &std::cout);
    int             token;

    while((token = lexer.yylex()) != 0)
    {
        std::string  tok(lexer.YYText(), lexer.YYText() + lexer.YYLeng());
        std::cout << "Token: " << token << "(" << tok << ")\n";
    }
}

Сложение

% flex split.lex
% g++ main.cpp lex.yy.cc

Выполнить (для предварительно обработанного файла)

% cat testfile | ./a.exe
Token: 3(Here is some text)
Token: 2(
)
Token: 1(")
Token: 3(here is another line)
Token: 1(")
Token: 2(
)
Token: 3(And another line)
1 голос
/ 30 ноября 2010

Вы можете использовать string::find_first_of и string::substr. Просто будьте осторожны, чтобы проверить наличие «пустых» строк; find_first_of найдет char с, поэтому \r и \n будут разделены результирующим алгоритмом.

В качестве альтернативы, переберите всю строку и скопируйте предыдущую часть, когда вы встретите другой разделитель.

1 голос
/ 30 ноября 2010

Разделите проблему следующим образом:

  1. У меня есть указатель на подстроку.Как найти следующую подстроку?
  2. У меня есть указатель на подстроку.Как добавить его в качестве следующего элемента в массив?

Теперь решите 1 и 2. Если возникнут проблемы, задайте еще раз.

1 голос
/ 30 ноября 2010

getline имеет дополнительный разделитель, поэтому вы можете использовать stringstream, чтобы сделать это без особых усилий с вашей стороны.Недостатком является то, что (я считаю) он работает только с одним разделителем за раз.

0 голосов
/ 10 декабря 2010

strtok заменит ваши токены на NULL.Вот почему он не включает токены.

man strtok для получения дополнительной информации.Я также играю со strtok и strtok_r, так как у меня есть входящий массив символов следующего значения:

Hello ~ Milktea ~ Это мое сообщение1005 *

Я собираюсь сначала раздеть ~ (тильды), а затем \ r \ n, или наоборот.

0 голосов
/ 01 декабря 2010

Вот метод, который использует функции регулярного выражения TR1.

std::string text("Here is some text\r\n\"here is another line\"\r\nAnd another line");
std::vector<std::string> vec;

std::regex rx("[\\w ]+|\\r\\n|\"");
std::sregex_iterator rxi(text.begin(), text.end(), rx), rxend;

for (; rxi != rxend; ++rxi)
{
    vec.push_back(rxi->str());
}

В моем тестировании это заполняет вектор 7 подстроками в вашем примере.Я не эксперт, поэтому может быть более правильное регулярное выражение, чем то, которое я использую.

...