5

I'm making a simple calculator where you type values into an edit box. I need to split the string into a number of arrays depending on how many *+-/ there are in the sum for instance

I have 22+22*22-22/22 I want to break that into five different arrays because there are five different groups of numbers. Then later I am going to add array1 to array two multiply that by array3 and subtract that by array4 and divide that by array 5.

CRABOLO
  • 8,605
  • 39
  • 41
  • 68
user744061
  • 51
  • 2
  • Why do you want them to be arrays? What language? – Carl Norum May 08 '11 at 17:19
  • Tag says delphi, so I suppose that is the language – Eponymous May 08 '11 at 17:34
  • @carl I'd guess the language is Delphi, as it's the only language listed in the tags. – Mason Wheeler May 08 '11 at 17:35
  • 1
    If you do as you say, and add the first two numbers, and then multiply the result by 22, you are doing it all wrong. For example, 2 + 3 × 5 = 17. 2 + 3 × 5 <> 25. Your expression above is 22 + 22×22 - 22/22 = 22 + 484 - 1 = 505. – Andreas Rejbrand May 08 '11 at 17:52
  • 1
    If you needed to split a string into an array you could use my [`Split`](http://stackoverflow.com/questions/4358064/how-to-paste-data-from-excel-into-cxgrid) function. But actually you need an expression parser. – David Heffernan May 08 '11 at 17:57
  • @Eponymous, @Mason, in my defense that tag wasn't there when I wrote my original comment. – Carl Norum May 09 '11 at 00:12

4 Answers4

4

If you want to read something like that, especially if you want to evaluate mathematical expressions, you need more than just an array-splitter; you need a real parser. Doing it right requires a bit of compiler theory. I'd recommend you take a look at Let's Build A Compiler, a tutorial that covers everything you'll need to know about expression parsing (and a bit more, since he's actually building a simple compiler) and makes it easy to understand. All examples are in Turbo Pascal, so it should be easy for a Delphi coder to read.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
2

Delphi XE has a SplitString function that does exactly what you need.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
  • Hardly. OP's question title is misleading. Splitting is the easy bit, it's the expression parsing that presents the challenges. As an off-topic aside, and as someone without XE, how efficient is `SplitString`? – David Heffernan May 08 '11 at 20:15
  • @David: If the challenge is only to evaluate an expression as shown, the split array approach seems quite valid to me and a complete expression parser might be overkill here. Regarding the efficiency of SplitString: how can I measure that or compare it against what? – Uwe Raabe May 09 '11 at 07:13
  • 1
    @Uwe Once you've split the string, how do you know how to combine the various numbers? My question about `SplitString()` is, essentially, does it do anything daft like the `SetLength(ResultArray, Length(ResultArray) + 1)` anti-pattern that `IOUtils.TDirectory.DoGetFiles()` does? – David Heffernan May 09 '11 at 08:02
  • @David: It counts the number of splitpoints by iterating over the string counting the delimiters. The array is allocated only once. Then it parses the string again to extract the parts. Each check for delimiter needs a StrScan as there can be more than multiple delimiters. – Uwe Raabe May 09 '11 at 17:35
  • @David: Once you have split the string it is easy to get the needed operation from the delimiter following the current string. You only have to count the number of characters handled, which is just adding the length of each handled string plus 1 for each handled delimiter. Seems not that complicated to mee. Depends on wether you need to obey the "point over line" rule (is it called that way?). – Uwe Raabe May 09 '11 at 17:42
  • @Uwe Thanks. Sounds like SplitString is quite well written. If you wanted to parse an expression it would be more natural to extract the operators as you walk the string, but you could build it on top of SplitString I guess. – David Heffernan May 09 '11 at 17:55
0

If you wish to get the result of that equation, you should try a non-visual component, called CalcExpress. It's free and you can get it from here: CalcExpress

Download link is at the end of the page text

beerwin
  • 9,813
  • 6
  • 42
  • 57
0

Here's a function which may help you on the way.

It breaks down an input string into an array of sub-strings, based upon a provided set of pre-defined character sets.

It will give you an array of strings, which will be ["22", "+", "22", "*", "22", "-", "22", "/", "22"].

From there on you'll have to identify the numbers and the operators, and you'll have to group and execute the calculations according to the rules for operator precedence.

TCharSet = Set of Char;
TStringArray = Array of String;

function GetSubStrings(InputString: String; CharacterSets: Array of TCharSet): TStringArray;
// Get Sub-strings
var
  Index: Integer;
  Character: Char;
  SubString: String;
  SubStringArray: TStringArray;
  CharacterSetIndex: Integer;
  PreviousCharacterSetIndex: Integer;
begin
  // Get
  SubString := '';
  SetLength(SubStringArray, 0);
  PreviousCharacterSetIndex := -1;
  for Index := 1 to Length(InputString) do
  begin
    // Character
    Character := InputString[Index];

    // Character Set Index
    CharacterSetIndex := GetCharacterSet(Character, CharacterSets);

    // Add
    if (CharacterSetIndex = PreviousCharacterSetIndex) or (Index = 1) then
      // Add Character to SubString
      SubString := SubString + Character
    else
    begin
      // Add SubString To SubString Array
      SetLength(SubStringArray, Length(SubStringArray) + 1);
      SubStringArray[Length(SubStringArray) - 1] := SubString;

      // New SubString
      SubString := Character;
    end;

    // Previous Character Set Index
    PreviousCharacterSetIndex := CharacterSetIndex;

    // Add last SubString
    if Index = Length(InputString)  then
    begin
      // Add SubString To SubString Array
      SetLength(SubStringArray, Length(SubStringArray) + 1);
      SubStringArray[Length(SubStringArray) - 1] := SubString;
    end;
  end;

  // Result
  Result := SubStringArray;
end; 

function GetCharacterSet(Character: Char; CharacterSets: Array of TCharSet): Integer;
// Get Character Set
var
  Index: Integer;
  CharacterSet: TCharSet;
begin
  // Get
  Result := -1;
  for Index := 0 to Length(CharacterSets) - 1 do
  begin
    // Character Set
    CharacterSet := CharacterSets[Index];

    // Check
    if Character in CharacterSet then
    begin
      // Result
      Result := Index;

      // Break
      Break;
    end;
  end;
end;
bjaastad_e
  • 691
  • 6
  • 10