|
Вопрос # 853/ вопрос решён / |
|
Приветствую, уважаемые эксперты!
У меня возник такой вопрос по парсингу строки, строку вида "7-13,6,22-40,99,54,123..." нужно разбить на составляющие числа, причем "1-13" все числа в промежутке от одного до тринадцати. Результат - получить каждое число в отдельности и те которые находятся в промежутке в первоначальном порядке.
Я все это делал с помощью pos, разбивая на части (раздилитель запятая), потом проверял наличие в каждой части "-", потом же с тем же pos определял начало и конец цикла для получения каждого числа промежутка. И затем выводил по такому же порядку как в первоначальной строке.
Есть ли более быстрый и простой способ для достижения такого же результата? Заранеее спасибо!
 |
Вопрос задал: Phoenix (статус: Посетитель)
Вопрос отправлен: 14 августа 2007, 17:18
Состояние вопроса: решён, ответов: 3.
|
Ответ #1. Отвечает эксперт: Вадим К
Здравствуйте, Phoenix!
Я подскажу как сделать начальное разбитие.
где то такой код
var sl:TStringList;
begin
sl:=TStringList.create;
sl.delimeterchar:=\',\';
sl.delimetertext:=\'7-13,6,22-40,99,54,123\';
//Всё теперь мы имеем в sl.count количество последовательностей, а в sl[0] = \'7-13\', sl[1] = \'6\', sl[2] = \'22-40\'
sl.free;
end;
Ну а дальше уже легче
 |
Ответ отправил: Вадим К (статус: Академик)
Время отправки: 14 августа 2007, 17:25
Оценка за ответ: 5
Комментарий к оценке: Спасибо огромное! Я с Delimiter и DelimitedText никокда не работал, а теперь буду знать!
|
Ответ #2. Отвечает эксперт: Матвеев Игорь Владимирович
Здравствуйте, Phoenix!
Алгоритмически более быстрое решение наврятли возможно. Как ни крути, но разбирая строку, нужно делить ее на составляющие по запятым, как ни крути нужно организовывать цикл для восстановления интервалов.
Другое дело, что Ваш вариант может быть не максимально продуктивен или, например иметь потенциальные подводные камни (от бесконечных циклов, до переполнения буфера). Существует множество библиотек парсинга и их можно было бы применить и в Вашем случае, может быть не для собственно парсинга, а посмотреть некоторые реализации и использовать у себя.
Ответ #3. Отвечает эксперт: min@y™
По роду своей деятельности на работе мне предстоит написать программу управления устройством контроля монтажа электронных модулей, проще говоря - устройством прозвонки. Там должна быть заложена такая функция как прозвонка контактов, заданных пользователем, который будет их вводить именно так: "7-13,6,22-40,99,54,123...". Поэтому я вчера решил написать тебе (и, естественно, себе) работающую на 100% функцию разбора таких конструкций. Вот она:
function ParsePageNumbers(const S: PChar; Numbers: TList): Boolean;
var
Index: Integer;
Len, Interval: Cardinal;
sBegin, sEnd: string; // Начальное и конечное значение интервала (строковые)
BeginNumber, EndNumber: Cardinal; // Начальное и конечное значение интервала (неотрицательные числа)
IsInterval, // Флаг поиска конца интевала (нашли "-" после числа)
DigitExpected: Boolean; // Флаг поиска нового числа (после "," и "-")
begin
Result:= false; // По умолчанию
Numbers.Clear;
Len:= StrLen(S); // Длина строки
if (Len = 0) or not (S[0] in [\'0\'..\'9\'])
then Exit; // строка должна быть непустой и начинаться с цифры
// Инициализация переменных
sBegin:= \'\';
sEnd:= \'\';
IsInterval:= false;
DigitExpected:= false;
Index:= -1; // !!!
// Цикл разбора строки
repeat
Inc(Index);
case S[Index] of
\'0\'..\'9\': begin // Нашли цифру
// Добавляем цифру в начало или конец интервала
if IsInterval
then sEnd:= sEnd + S[Index]
else sBegin:= sBegin + S[Index];
DigitExpected:= false; // След. символ - не обязательно цифра
end;
\',\', #0: begin // Конец интервала или всей строки
if DigitExpected
then Exit; // Ошибка: ожидалась цифра
if IsInterval // если ищем конец интервала, то
then begin
BeginNumber:= StrToInt(sBegin); // Начало
EndNumber:= StrToInt(sEnd); // конец
// Далее формируем интервал по возрастанию
// или убыванию соответственно
if BeginNumber <= EndNumber
then for Interval:= BeginNumber to EndNumber do // вперёд
Numbers.Add(Pointer(Interval))
else for Interval:= BeginNumber downto EndNumber do // назад
Numbers.Add(Pointer(Interval));
end
else Numbers.Add(Pointer(StrToInt(sBegin))); // иначе сразу добавляем в список
DigitExpected:= true; // След. символ - обязательно цифра!
IsInterval:= false; // Ищем начало след. интервала или единичное число
sBegin:= \'\'; // Очистка
sEnd:= \'\'; // временных переменных
end;
\'-\': begin // середина интервала
if DigitExpected
then Exit; // Ошибка: ожидалась цифра
IsInterval:= true; // Установка
DigitExpected:= true; // флагов
end;
else Exit; // Ошибка: недопустимый символ
end; //case
until S[Index] = #0; // До конца строки
Result:= true; // Успешно
end;
Полный пример использования этой функции находится в прицепе. УДАЧИ! К ответу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки ответа)
 |
Ответ отправил: min@y™ (статус: Доктор наук)
Время отправки: 16 августа 2007, 08:14
Оценка за ответ: 5
Комментарий к оценке: Спасибо, за пример! Выглядит немного устрашающе, зато работает как надо, думаю очень пригодится.
|
Мини-форум вопроса
Всего сообщений: 1; последнее сообщение — 16 августа 2007, 14:36; участников в обсуждении: 1.
|
min@y™ (статус: Доктор наук), 16 августа 2007, 14:36 [#1]:
Выглядит страшно, потому что сервевр обрезает всё форматирование кода. Отформатированный код выглядит очень симпотно.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
31 января 2011, 20:02: Статус вопроса изменён на решённый (изменил модератор Ерёмин А.А.): Автоматическая обработка (2 и более ответов с оценкой 5)
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|