Мне нужно иметь возможность анализировать следующие две строки в моей программе:
cat myfile || sort
more myfile || grep DeKalb
Строка сохраняется в буфере символов [1024]. В итоге мне нужно указать указатель на массив символов для левой стороны и указатель на массив символов для правой стороны, чтобы я мог использовать их для вызова следующего для каждой стороны:
int execvp(const char *file, char *const argv[]);
У любого есть идеи, как мне получить правильные аргументы для команды execvp, если две вышеупомянутые строки сохранены в символьном буфере символьный буфер [1024]; ?
Мне нужно, чтобы char * left содержал первое слово левой стороны, затем char * const leftArgv [] для хранения обоих слов слева. Тогда мне нужно то же самое для права. Я уже два часа бездельничаю со strtok, и я бью стену. У кого-нибудь есть идеи?
Я рекомендую вам узнать больше о регулярные выражения. И чтобы решить вашу проблему безболезненно, вы можете использовать библиотека Boost.regex библиотека, которая обеспечивает мощный механизм регулярных выражений. Решением будет всего несколько строк кода, но я призываю вас сделать это самостоятельно — это было бы хорошим упражнением. Если у вас все еще есть проблемы, вернитесь с некоторыми результатами и четко укажите, где вы застряли.
Вы можете использовать std :: getline (stream, stringToReadInto, delimeter).
Я лично использую свою собственную функцию, в которую встроены некоторые дополнительные функции, которая выглядит следующим образом:
StringList Seperate(const std::string &str, char divider, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
{
return Seperate(str, CV_IS(divider), seperationFlags, whitespaceFunc);
}
StringList Seperate(const std::string &str, CharValidatorFunc isDividerFunc, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
{
bool keepEmptySegments = (seperationFlags & String::KeepEmptySegments);
bool keepWhitespacePadding = (seperationFlags & String::KeepWhitespacePadding);
StringList stringList;
size_t startOfSegment = 0;
for(size_t pos = 0; pos < str.size(); pos++)
{
if(isDividerFunc(str[pos]))
{
//Grab the past segment.
std::string segment = str.substr(startOfSegment, (pos - startOfSegment));
if(!keepWhitespacePadding)
{
segment = String::RemovePadding(segment);
}
if(keepEmptySegments || !segment.empty())
{
stringList.push_back(segment);
}
//If we aren't keeping empty segments, speedily check for multiple seperators in a row.
if(!keepEmptySegments)
{
//Keep looping until we don't find a divider.
do
{
//Increment and mark this as the (potential) beginning of a new segment.
startOfSegment = ++pos;
//Check if we've reached the end of the string.
if(pos >= str.size())
{
break;
}
}
while(isDividerFunc(str[pos]));
}
else
{
//Mark the beginning of a new segment.
startOfSegment = (pos + 1);
}
}
}
//The final segment.
std::string lastSegment = str.substr(startOfSegment, (str.size() - startOfSegment));
if(keepEmptySegments || !lastSegment.empty())
{
stringList.push_back(lastSegment);
}
return stringList;
}
Где ‘StringList’ является typedef станд :: вектор, и CharValidatorFunc — указатель на функцию (фактически, std :: function, чтобы разрешить поддержку функтора и лямбды) для функции, принимающей один символ и возвращающей логическое значение. это можно использовать так:
StringList results = String::Seperate(" Meow meow , Green, \t\t\nblue\n \n, Kitties!", ',' /* delimeter */, DefaultFlags, is_whitespace);
И вернул бы результаты:
{«Мяу мяу», «Зеленый», «синий», «Котята!»}
Сохранение внутреннего пробела «Мяу мяу», но удаление пробелов, вкладок и новых строк, окружающих переменные, и разделение запятыми.
(CV_IS является объектом функтора для сопоставления определенного символа или определенной коллекции символов, взятых как строковый литерал. У меня также есть CV_AND и CV_OR для объединения функций валидатора символов)
Для строкового литерала я бы просто бросил его в std :: string () и затем передал бы его функции, если не требуется экстремальная производительность. Взломать разделители довольно легко, так как эту функцию настраивают в соответствии с типичным использованием и требованиями моих проектов, но вы можете изменить ее и заявить о себе.
В случае, если это доставит кому-то еще горе, я решил проблему следующим образом:
//variables for the input and arguments
char *command[2];
char *ptr;
char *LeftArg[3];
char *RightArg[3];
char buf[1024]; //input buffer
//parse left and right of the ||
number = 0;
command[0] = strtok(buf, "||");
//split left and right
while((ptr=strtok(NULL, "||")) != NULL)
{
number++;
command[number]=ptr;
}
//parse the spaces out of the left side
number = 0;
LeftArg[0] = strtok(command[0], " ");
//split the arguments
while((ptr=strtok(NULL, " ")) != NULL)
{
number++;
LeftArg[number]=ptr;
}
//put null at the end of the array
number++;
LeftArg[number] = NULL;
//parse the spaces out of the right side
number = 0;
RightArg[0] = strtok(command[1], " ");
//split the arguments
while((ptr=strtok(NULL, " ")) != NULL)
{
number++;
RightArg[number]=ptr;
}
//put null at the end of the array
number++;
RightArg[number] = NULL;
Теперь вы можете использовать LeftArg и RightArg в команде, после того как вы правильно настроили трубопровод
execvp(LeftArg[0], LeftArg);//execute left side of the command
Затем направьте трубку к правой стороне команды и выполните команду
execvp(RightArg[0], RightArg);//execute right side of command