2014-03-12 2 views
-3

Я новичок в Delphi XE5 (входит в состав RAD Studio Embarcadero) и использует функцию StrToFloat в проекте VCL Forms, предназначенном для создания простого калькулятора.'' Недействительный идентификатор (Delphi XE5)

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

Затем я хочу извлечь числа относительно операторов, итерации по строкам памятки. Для 3^4, вы увидите ...

3 
^ 
4 

... в TMemo.

Я хочу, чтобы найти^знак с индексом линии 1 (строки начинаются с индекса 0, верно?), И хранить 3 в base переменной логикой, что если ^ является lines[1], то 3 является lines[1-1], или lines[0], и хранить 4 в переменной exponent. Обе переменные были бы расширены по типу. Это код, который я создал, чтобы сделать это ...

procedure TForm1.btnEqualsClick(Sender: TObject); 
var 
    i: Integer; 
    base: extended; 
    exponent: extended; 
    result: extended; 
begin 
    {This For loop looks for the exponentiation operator (^) in memCurrentEntry. If 
    it's found, it then solves the equation.} 
    for i := Low(memCurrentEntry.Lines.Text.Length) to High(memCurrentEntry.Lines.Text.Length) do 
    if AnsiContainsStr(memCurrentEntry.Lines.Text, '^') then 
    begin 
     base := StrToFloat(memCurrentEntry.Lines[ansipos('^', memCurrentEntry.Lines.Text)-1]); 
     exponent := StrToFloat(memCurrentEntry.Lines[ansiPos('^', memCurrentEntry.Lines.Text)+2]); 
     result := power(base, exponent); 
    end; 

Когда я бегу калькулятор, цифры отображаются правильно, но когда я нажал на кнопку равно для запуска кода выше, я получаю сообщение Project Calculator_u.exe повышен класс исключений EConvertError с сообщением '' 'не является допустимым значением с плавающей запятой'.

Я знаю, что функция StrToFloat пытается преобразовать нулевой символ или что-то (How do I identify what code is generating " '' is not a valid floating point value" error dialogue box), но что мне делать, чтобы исправить это?

Ниже приведен код для каждой кнопки - цифра (0, 1, 2, 3 и т.д.) изменения, но в остальном то же самое для каждого из них ...

procedure TForm1.btn0Click(Sender: TObject); 
begin 
    //Adds the digit 0 to the end of the current number in memCurrentEntry 
    memCurrentEntry.SelStart := Length(memCurrentEntry.Text); 
    memCurrentEntry.Lines.Text := Copy(memCurrentEntry.Lines.Text,1, 
    memCurrentEntry.SelStart)+'0'+ Copy(memCurrentEntry.Lines.Text, 
    memCurrentEntry.SelStart+1,Length(memCurrentEntry.Lines.Text) 
    - memCurrentEntry.SelStart); 

    //Adds the digit 0 to the end of the current number in edtCurrentEntry 
    edtcurrententry.Text := edtcurrententry.Text + '0'; 
end; 

я могу отправьте полный файл блока по запросу.

+0

Не могли бы вы исправить заголовок вопроса. Q не имеет ничего общего с * '' Не является допустимым идентификатором * –

+0

Прежде всего, Добро пожаловать в сообщество Delphi! Здесь много информации, которая не помогает идентифицировать вопрос. Одна из проблем с этим кодом заключается в том, что он предполагает, что a^всегда будет иметь предыдущее число, поэтому ответ Дэвида на использование TryStrToFloat будет решать эту конкретную проблему. – skamradt

ответ

3

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

var 
    str: string; 
    val: Double; 
.... 
if TryStrToFloat(str, val) then 
    // val contains the floating point value represented by str 
else 
    // str does not contain a floating point value, do something else with it 

Разумеется, вы можете использовать StrToFloat и поймать исключение. Но так как вы ожидаете столкнуться с исключением, это приведет к значительно более чистым кодам, если вы используете TryStrToFloat.

+0

Хорошо. В чем преимущество этого? Будет ли TryStrToFloat выполняться после обнаружения исключения? Как обрабатывать исключение в Pascal/Delphi? (Я делал это только несколько недель). – Batfan1939

+0

Пожалуйста, не просите нас научить вас здесь. Пожалуйста, придерживайтесь конкретных вопросов. Если вы хотите знать, что делает 'TryStrToFloat', следуйте ссылке на документы в ответе. Надеюсь, вы это уже сделали. Не так ли? –

+0

Не понимал, что это была ссылка. Я не прошу вас научить меня языку, я просто пытаюсь понять ваш ответ. – Batfan1939

0

использование линий на памятке неправильно:

base := StrToFloat(memCurrentEntry.Lines[ansipos('^', memCurrentEntry.Lines.Text)-1]); 

lines.text возвращает весь текст, который не то, что вы хотите. Вместо этого используйте некоторые LOCAL-переменные для хранения ваших значений поиска ...Таким образом, вы можете установить точку останова и увидеть, что не так и использовать следующий метод, чтобы найти «^»

result := 0; 
carrotLine := memCurrentEntry.Lines.IndexOf('^'); 
if carrotline > 0 then // must be 1 or greater, so a number can be at the 0 position 
    begin 
    base := TryStrToFloat(MemCurrentEntry.Lines[carrotLine-1],0); 
    exponent := 0; 
    // only try to read the next value if there is one. 
    if memCurrentEntry.Lines.Count >= carrotLine then 
     exponent := TryStrToFloat(MemCurrentEntry.Lines[carrotline+1],0); 
    result := power(base,exponent); 
    end; 

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

+0

Любые рекомендации? Я хотел бы выполнить несколько вычислений за раз, вроде встроенного калькулятора Microsoft или большинства научных калькуляторов. Как только я получу эту работу для каретки, я применим ее к другим операндам/операторам/независимо. Я понимаю суть вашего предложения, но не специфику его реализации. – Batfan1939

+0

проще всего использовать стек. Концепция стека, где вы нажимаете и поп, работает очень хорошо. Подумайте об этом, введите номер, нажмите оператор, нажимает номер на стек и сохраняет оператора. Если оператор «=», то посмотрите на оператора и выскочите переменные, отбросив результат. так что 2 + 2 = выскочил бы и 2 входа (стека теперь пуст) выполнить добавление и нажать 4 в стеке. входящий в то, что * 2 выскочит из 2 и 4 из стека, умножьте их и поместите 8 в стек ... ясный, конечно, очистит стек. – skamradt

+0

OT: @skamradt, вы можете попросить модераторов объединить ваш профиль со старым. – TLama

0

Использование StrToFloat не является ошибкой. Если преобразование не выполнено, пользователь должен увидеть сообщение об ошибке. Если вы хотите подавить ошибку тихо, то вам следует добавить попытку/кроме защиты вашего кода.

try 
    Value := StrToFloat(A_String); 
except 
    on EConvertError do 
    Value := 0; // Fallback to a default value or execute other code logic 
end; 

Согласно вашему данному примеру коды, если основание и показатель степени вводятся в вашем заданном формате (первая строкой является базой, вторая линия является «^» и третья строка показатель). Я предлагаю вам написать свой код следующим образом:

var 
    Numbers: TArray<string>; 
    // Other variables go here 
begin 
    // ... 
    Numbers := memCurrentEntry.Lines.Text.Split('^'); 
    if Length(Numbers) = 2 then 
    try 
    Base := StrToFloat(Numbers[0]); 
    Exponent := StrToFloat(Numbers[1]); 
    Result := Power(Base, Exponent); 
    except 
    on EConvertError do 
    begin 
     ShowMessage(Format('Unable to calculate the formula %s', [memCurrentEntry.Lines.Text])); 
     Result := 0; // Fallback to a default value, such as 0 
    end; 
    end; 
    // ... 
end;