On 9/20/13, Reinier Olislagers <reinierolislag...@gmail.com> wrote: > The question however becomes "what is the > algorithm for deciding invalid characters" which IMO will become a mess > very quickly. Much better to just consider the entire input as invalid. >
Here's my implementation: program test; {$mode objfpc} {$H+} uses SysUtils, StrUtils; function TryRomanToInt(S: String; out N: Integer): Boolean; var i, Len: Integer; Terminated: Boolean; begin Result := (False); S := UpperCase(S); //don't use AnsiUpperCase please Len := Length(S); if (Len = 0) then Exit; i := 1; N := 0; Terminated := False; //leading M's while (i <= Len) and (S[i] = 'M') do begin //writeln('TryRomanToInt: Found 1000'); Inc(i); N := N + 1000; end; //then CM or or CD or D or (C, CC, CCC, CCCC) if (i <= Len) and (S[i] = 'D') then begin //writeln('TryRomanToInt: Found 500'); Inc(i); N := N + 500; end else if (i + 1 <= Len) and (S[i] = 'C') then begin if (S[i+1] = 'M') then begin //writeln('TryRomanToInt: Found 900'); Inc(i,2); N := N + 900; end else if (S[i+1] = 'D') then begin //writeln('TryRomanToInt: Found 400'); Inc(i,2); N := N + 400; end; end ; //next max 4 C's if (i <= Len) and (S[i] = 'C') then begin //find max 4 C's //writeln('TryRomanToInt: Found 100'); Inc(i); N := N + 100; if (i <= Len) and (S[i] = 'C') then begin //writeln('TryRomanToInt: Found 100'); Inc(i); N := N + 100; end; if (i <= Len) and (S[i] = 'C') then begin //writeln('TryRomanToInt: Found 100'); Inc(i); N := N + 100; end; if (i <= Len) and (S[i] = 'C') then begin //writeln('TryRomanToInt: Found 100'); Inc(i); N := N + 100; end; end; //then XC or XL if (i + 1 <= Len) and (S[i] = 'X') then begin if (S[i+1] = 'C') then begin //writeln('TryRomanToInt: Found 90'); Inc(i,2); N := N + 90; end else if (S[i+1] = 'L') then begin //writeln('TryRomanToInt: Found 40'); Inc(i,2); N := N + 40; end; end; //then L if (i <= Len) and (S[i] = 'L') then begin //writeln('TryRomanToInt: Found 50'); Inc(i); N := N + 50; end; //then (X, xx, xxx, xxxx) if (i <= Len) and (S[i] = 'X') then begin //find max 4 X's //writeln('TryRomanToInt: Found 10'); Inc(i); N := N + 10; if (i <= Len) and (S[i] = 'X') then begin //writeln('TryRomanToInt: Found 10'); Inc(i); N := N + 10; end; if (i <= Len) and (S[i] = 'X') then begin //writeln('TryRomanToInt: Found 10'); Inc(i); N := N + 10; end; if (i <= Len) and (S[i] = 'X') then begin //writeln('TryRomanToInt: Found 10'); Inc(i); N := N + 10; end; end; //then IX or IV if (i + 1 <= Len) and (S[i] = 'I') then begin if (S[i+1] = 'X') then begin Terminated := (True); //writeln('TryRomanToInt: Found 9'); Inc(i,2); N := N + 9; end else if (S[i+1] = 'V') then begin Terminated := (True); //writeln('TryRomanToInt: Found 4'); Inc(i,2); N := N + 4; end; end; //then V if (not Terminated) and (i <= Len) and (S[i] = 'V') then begin //writeln('TryRomanToInt: Found 5'); Inc(i); N := N + 5; end; //then I if (not Terminated) and (i <= Len) and (S[i] = 'I') then begin Terminated := (True); //writeln('TryRomanToInt: Found 1'); Inc(i); N := N + 1; //Find max 3 closing I's if (i <= Len) and (S[i] = 'I') then begin //writeln('TryRomanToInt: Found 1'); Inc(i); N := N + 1; end; if (i <= Len) and (S[i] = 'I') then begin //writeln('TryRomanToInt: Found 1'); Inc(i); N := N + 1; end; if (i <= Len) and (S[i] = 'I') then begin //writeln('TryRomanToInt: Found 1'); Inc(i); N := N + 1; end; end; //writeln('TryRomanToInt: Len = ',Len,' i = ',i); Result := (i > Len); //if Result then writeln('TryRomanToInt: N = ',N); end; var S: String; N1, N2: Integer; B: Boolean; begin repeat write('Enter Roman numeral: '); readln(S); B := TryRomanToInt(S, N1); if B then write('TryRomanToInt(''',S,''') -> ',N1) else write('TryRomanToInt(''',S,''') FAIL'); writeln; N2 := StrUtils.RomanToInt(S); writeln('StrUtils.RomanToInt(''',S,''') = ',N2); if B and (N1 <> N2) then writeln('StrUtils.RomanToInt <> TryRomanToInt'); writeln; until S = ''; end. Bart _______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal