2013-02-20 2 views
2

Я пытаюсь написать Ада, эквивалентную методу split() в Java или C++. Я должен ввести строку и целое число и вывести два отдельных строковых значения. Например: раскол «привет» и 2 вернется: «Первая часть он и вторая часть LLO»ada split() метод

код, который я имею следующим образом:

-- split.adb splits an input string about a specified position. 
-- 
-- Input: Astring, a string, 
--  Pos, an integer. 
-- Precondition: pos is in Astring'Range. 
-- Output: The substrings Astring(Astring'First..Pos) and 
--      Astring(Pos+1..Astring'Last). 
-------------------------------------------------------------- 

with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Strings.Fixed; 
use Ada.Text_IO, Ada.Integer_Text_IO, Ada.Strings.Fixed; 

procedure Split is 

    EMPTY_STRING : String := "          "; 

    Astring, Part1, Part2 : String := EMPTY_STRING; 
    Pos, Chars_Read  : Natural; 

    ------------------------------------------------ 
    -- Split() splits a string in two.   
    -- Receive: The_String, the string to be split, 
    --   Position, the split index.   
    -- PRE: 0 < Position <= The_String.length(). 
    --  (Ada arrays are 1-relative by default) 
    -- Passback: First_Part - the first substring, 
    --   Last_Part - the second substring. 
    ------------------------------------------------ 
    function Split(TheString : in String ; Pos : in Integer; Part1 : out String ; Part2  : out String) return String is 
    begin 
    Move(TheString(TheString'First .. Pos), Part1); 
    Move(TheString(Pos .. TheString'Last), Part2); 
    return Part1, Part2; 
    end Split; 



begin           -- Prompt for input 
    Put("To split a string, enter the string: "); 
    Get_Line(Astring, Chars_Read); 
    Put("Enter the split position: "); 
    Get(Pos); 

    Split(Astring, Pos, Part1, Part2); 

    Put("The first part is "); 
    Put_Line(Part1); 
    Put(" and the second part is "); 
    Put_Line(Part2); 

end Split; 

Главная у меня возникают проблемы с возвратом двух отдельных значений строк и вообще всей функции split(). Любые указатели или помощь приветствуются. Спасибо

+0

+1 для (почти) [sscce] (http://sscce.org/). – trashgod

+0

@trashgod спасибо Я пробовал :) – ola

ответ

3

Вместо function рассмотрите вопрос о создании Split a procedure с двумя параметрами out, как вы показали. Затем определите, является ли Posпоследним индекс Part1 или первый индекс Part2; Я выбрал последнее.

procedure Split(
    TheString : in String; Pos : in Integer; 
    Part1 : out String; Part2 : out String) is 
begin 
    Move(TheString(TheString'First .. Pos - 1), Part1); 
    Move(TheString(Pos .. TheString'Last), Part2); 
end Split; 

Обратите внимание, что String индексов Positive:

type String is array(Positive range <>) of Character; 
subtype Positive is Integer range 1 .. Integer'Last; 
+0

Я вижу, как это сработает. Тем не менее, я получаю сообщение об ошибке «повышенный CONSTRAINT_ERROR: split.adb: 38 range check failed» при запуске программы – ola

+2

понял это! Спасибо за это :) – ola

+1

У меня есть пара проблем с этим: строки вывода - это не строки, а буферы Ada 'String'. Чтобы использовать их, клиент должен выполнить некоторую дополнительную математику, чтобы определить длину действительных данных в них. Кроме того, клиент должен выполнить некоторую математику, чтобы убедиться, что оба буфера достаточно велики. Первая проблема может быть исправлена ​​с двумя дополнительными параметрами для длин и еще несколькими строками кода. Второе требует использования Ada.Strings.Unbounded. –

3

От глядя через код, который вы действительно нужно прочитать вообще на String type, потому что вы притягивая много ожиданий в других языках о том, как работать с ними, - которые Арен» t будет работать с ними. Стиль String Ada не является одним из его более гибких функций, поскольку они всегда фиксированная длина. Хотя есть способы обойти ограничения в такой ситуации, как вы описываете, было бы гораздо проще просто использовать Unbounded_Strings.

Ввод строки String в вашу функцию может оставаться от строки String, которая будет регулировать длину строки, которую вы ему предоставляете. Два выходных Unbounded_Strings затем просто устанавливаются на срезанные компоненты строки после вызова To_Unbounded_String() для каждого из них.

+0

Я знаю, что о различных типах струн в Аде! Для выполнения задания, тем не менее, я просто останусь с просто строкой String для простоты. – ola

+0

@ user1998581 - Если вы хотите простоты, вместо этого используйте Ada.Strings.Unbounded.Unbounded_String. Вы найдете, что они работают намного больше, чем строки Java (я предполагаю), к которым вы привыкли. Для обработки статических строк Ada требуется совершенно другое мышление (и процедура 'split' не является частью этого). –

+0

@ user1998581: Marc, Brian & T.E.D. предлагаем убедительные, практические советы. В то время как 'String' сам по себе немного примитивен, стандартная библиотека Ada предлагает множество строковых моделей с различными компромиссами. – trashgod

1

Учитывая ограничение основной программы, со всеми строками, ограниченных по размеру EMPTY_STRING. процедура с внешними параметрами - это правильный подход, при этом выделенное хранилище параметров выделяется вызывающим (в стеке, как это бывает)

Это не всегда так, поэтому стоит знать другой способ. Проблема заключается в том, как обращаться с данными, размер которых неизвестен до выполнения.

Некоторые языки могут предлагать только распределение времени выполнения в куче (через «новый» или «malloc») и могут получать доступ только к данным через указатели, оставляя множество беспорядочных проблем, включая доступ с конца данных (переполнение буфера) или правильно освободить память (утечки памяти, доступ к свободным указателям и т. д.)

Ada также позволит использовать этот метод, но обычно это не нужно и сильно не рекомендуется. Unbounded_String является оболочкой этого метода, а Bounded_String избегает выделения кучи, где вы можете принять верхнюю границу длины строки.

А также, Ada позволяет создавать структуры данных с переменным размером в стеке; метод просто включает в себя создание нового фрейма стека и объявление новых переменных, где вам нужно, с «объявить». Новые переменные могут быть инициализированы вызовами функций.

Каждая функция может возвращать только один объект, но размер этого объекта может быть определен во время выполнения. Таким образом, либо «Split» может быть реализован как 2 функции, возвращая Part1 или Part2, или он может вернуть запись, содержащую обе строки. Это будет запись с двумя дискриминаторами размера, поэтому я выбрал более простой вариант здесь. Результаты функции обычно создаются на месте (избегают копирования).

Для потока в вашем примере потребуется два вложенных блока Declare; если «Pos» может быть определен первым, они могут быть свернуты в один ...

procedure Split is 

    function StringBefore(Input : String; Pos : Natural) return String is 
    begin 
     return Input(1 .. Pos-1); 
    end StringBefore; 

    function StringFrom ... 

begin           
    Put("To split a string, enter the string: "); 
    declare 
     AString : String := Get_Line; 
     Pos  : Natural; 
    begin 
     Put("Enter the split position: "); 
     Get(Pos); 
     declare 
     Part1 : String := StringBefore(AString, Pos); 
     Part2 : String := StringFrom(AString, Pos); 
     begin 
     Put("The first part is "); 
     Put_Line(Part1); 
     Put(" and the second part is "); 
     Put_Line(Part2); 
     end; -- Part1 and Part2 are now out of scope 
    end;  -- AString is now out of scope 
end Split; 

Это, очевидно, может быть обернут в петле, с разными строками размера каждый раз, без проблем управления памяти.

3

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

Front_Half : constant String := Original(Original'first..Index); 
Back_Half : constant String := Original(Index+1..Original'last); 

Выполнено.

Обратите внимание, что статические строки Ada: очень отличается от строк на других языках, таких как C или Java. Из-за их статического характера они лучше всего построены либо встроенными, как я сделал выше, либо как возвращаемые значения из функций. Поскольку функции не могут возвращать более одного значения, единственная унифицированная подпрограмма «split» просто не подходит для статической обработки строки Ada. Вместо этого вы должны сделать то, что я сделал выше, вызвать соответствующие процедуры из Ada.Strings.Fixed (и Tail) или переключиться на использование Ada.Strings.Unbounded.Unbounded_String вместо String.

Последний, вероятно, самый простой вариант, если вы хотите сохранить свое мышление Java в отношении обработки строк. Если вы хотите действительно узнать Аду, я бы настоятельно посоветовал вам научиться разбираться со статическим фиксированным способом String с Адой.

+0

Я согласен с вашим [комментарием выше] (http://stackoverflow.com/a/14971565/230513) и +1 к вам, Марку и Брайану. Я думаю, что все три ответа подчеркивают достоинство выполнения этого упражнения в Ada как способ изучения различных способов моделирования строк. На большинстве других языков есть только один. – trashgod

+0

+1 для постоянных. Моя единственная говядина с этим (и я делаю это много) - это то, что это становится беспорядочным написанием парсера таким образом!Я пытаюсь научиться абстрактно над «Оригиналом (Index + 1..Original'last)» с простыми функциями, как в моем ответе, в попытке прояснить намерение. –

+0

@BrianDrummond - Ahhh. Ну, если вы пишете * парсер *, то я бы предложил несколько возможных изменений: 1. Используйте общий буфер «String» (с, конечно, отдельную переменную длины) и просто передавайте индексы вокруг. Не беспокойтесь, копируя данные из буфера, пока вам это не понадобится. 2. Не используйте Ada.Strings.Unbounded. Ada.Strings. ** Ограниченный ** может работать для вас, но на самом деле просто см. Пункт 1. 3. Вы можете рассмотреть [OpenToken] (http://www.stephe-leake.org/ada/opentoken.html) , который может сделать для вас много работы. –

Смежные вопросы