Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2003-11

opening files from a text list

16 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

DONALD PEDDER

As per my last question to the list, I'm sure there's a way to do this, but I'm not sure how. Last time I got a quick answer after I'd spent ages trying to work it out myself, so I'll ask first this time, instead of banging my head against the keyboard. :-)

I'll use the actual example I am working on, which relates to football games.

If I have a file which contains on the first line...

49ers at Giants 16 13

I want to open a file called "49ers" and a file called "Giants" and do some processing. Although FP handles strings, I believe that you can still only read a character at a time, so I don't know how to read "49ers" into a variable and open that file. The variable would be called Away say, so how do I get "49ers" into Away so that I can then do assign(awayteam,Away)? I would then want to read "Giants" into Home, and do assign(hometeam,Home), and go from there.
Some teams have the same initial, so just reading the first character fails to provide enough uniqueness. I know I could set up a complex set of embedded case statements (case first char -> case second char), but there's surely an easier way? That method would leave the team names hard-coded into the program, which isn't a very good way to do things.

thanks,
DONALD.

E-mail -
BIG DON's Home-page - http://jedi.apana.org.au/~jims_son Pedder Passer Rating - http://jedi.apana.org.au/~jims_son/PPR AusNFL mailing-list - http://jedi.apana.org.au/mailman/listinfo/ausnfl

"What I always wanted is to be accepted, not understood" - MAN RAY

Reply by email

DONALD PEDDER
to Anton Tichawa: Hello! You need string manipulation. Here is a simple example, dividing the line into…
Anton Tichawa wrote 17 lines
function scanblack(var s: string): string; var i: integer; begin i := 1; repeat if i > length(s) then begin break; end; if s[i] = ' ' then begin break; end; inc(i); until false; result := copy(s, 1, i - 1); delete(s, 1, i - 1); end;

When I compiled the code, I got "identifier not found result", so I added "result: string;", but even though it then compiles, the function returns garbage (not "49ers" in the first instance). The original line gets read in correctly ("49ers at Giants 16 13"), so the problem is after that. Should there be a line along the lines of "return result" in the function? I haven't really used functions much (at least not any that returned anything anyway).

This code helps me to understand a bit more (at least when I get time to sit down and look at it some more anyhow) - the above is a different approach to anything I've used before (having not used strings before), so I wouldn't have thought of it myself.

if scanblack(line) 'at' then begin writeln('syntax error');

I'm getting this coming up, presumably because the functions aren't quite working.

thanks,
dp.

Reply by email

Marco van de Voort
to DONALD PEDDER
Show quoted text 22 lines
On Fri, 28 Nov 2003, Anton Tichawa wrote: > function scanblack(var s: string): string; > var > i: integer; > begin > i := 1; > repeat > if i > length(s) then begin > break; > end; > if s[i] = ' ' then begin > break; > end; > inc(i); > until false; > result := copy(s, 1, i - 1); > delete(s, 1, i - 1); > end; When I compiled the code, I got "identifier not found result", so I added "result: string;",
Either you have to compile in Delphi modes (-Sd or -S2), or replace result:=
by scanblack:=
returns garbage (not "49ers" in the first instance).

That's because result is the name of the return value in Delphi, while it is the name of the function in TP.

By defining a result variable yourself, the return value gets lost.

Reply by email

Anton Tichawa
to DONALD PEDDER: As per my last question to the list, I'm sure there's a way to do this, but I'm not sure…

Hello!

Show quoted text 17 lines
If I have a file which contains on the first line... 49ers at Giants 16 13 I want to open a file called "49ers" and a file called "Giants" and do some processing. Although FP handles strings, I believe that you can still only read a character at a time, so I don't know how to read "49ers" into a variable and open that file. The variable would be called Away say, so how do I get "49ers" into Away so that I can then do assign(awayteam,Away)? I would then want to read "Giants" into Home, and do assign(hometeam,Home), and go from there. Some teams have the same initial, so just reading the first character fails to provide enough uniqueness. I know I could set up a complex set of embedded case statements (case first char -> case second char), but there's surely an easier way? That method would leave the team names hard-coded into the program, which isn't a very good way to do things.

You need string manipulation. Here is a simple example, dividing the line into "black" tokens separated by "white" spaces (it gets more complicated when dealing with tabs, numbers etc.):

program football;
var
  file0: text;
  line: string;
  away: string;
  home: string;
function scanblack(var s: string): string;
var
  i: integer;
begin
  i := 1;
  repeat
    if i > length(s) then begin
      break;
    end;
    if s[i] = ' ' then begin
      break;
    end;
    inc(i);
  until false;
  result := copy(s, 1, i - 1);
  delete(s, 1, i - 1);
end;
function scanwhite(var s: string): string;
var
  i: integer;
begin
  i := 1;
  repeat
    if i > length(s) then begin
      break;
    end;
    if s[i]  ' ' then begin
      break;
    end;
    inc(i);
  until false;
  result := copy(s, 1, i - 1);
  delete(s, 1, i - 1);
end;
begin
  assign(file0, '49ers');
  reset(file0);
  readln(file0, line);
  close(file0);
  scanwhite(line);
  away := scanblack(line);
  scanwhite(line);
  if scanblack(line)  'at' then begin
    writeln('syntax error');
    halt;
  end;
  scanwhite(line);
  home := scanblack(line);
  writeln('AWAY: ', away, '; HOME: ', home);
end.

hth,

Anton.

----------

Ing. Anton Tichawa
Volkertstrasse 19 / 20
A-1020 Wien
phone: +43 1 218 97 59
email:

----------

"Adas Methode war, wie sich zeigen wird, Tagträume in offenbar korrekte Berechnungen einzuweben."

Doris Langley Moore: Ada, Countess of Lovelace (London 1977).

----------

Reply by email

ZINTEL Gerhard

Hello Donald,

Show quoted text 16 lines
If I have a file which contains on the first line... 49ers at Giants 16 13 I want to open a file called "49ers" and a file called "Giants" and do some processing. Although FP handles strings, I believe that you can still only read a character at a time, so I don't know how to read "49ers" into a variable and open that file. The variable would be called Away say, so how do I get "49ers" into Away so that I can then do assign(awayteam,Away)? I would then want to read "Giants" into Home, and do assign(hometeam,Home), and go from there.

here is just another approach. The function NextToken scans a string for the next token and gives it back. At the same time it shortens the original sting. So with each call of it you'll get the next token available. It handles blanks and tabs as white space character and is easily extendible for other "white space" characters as ':', ';', ...

Here is the function with a short program for testing.

program TestNextToken;
var s : string;
  {-----------------------------------------------------------------------}
  function nextToken(var s:string):string;
  { reads next token from string s and shortens s by this amount
}
  {-----------------------------------------------------------------------}
  const whitespace = [' ',#9];	// whitespace should be blank and tab
  var l, start, stop : integer;
  begin
    l := length(s);
    start := 1;
    // searching first non whitespace character
    while (start <= l) and (s[start] in whitespace) do inc(start);
    stop:=start;
    // searching last non whitespace character
    while (stop <= l) and (not (s[stop] in whitespace)) do inc(stop);
    if s[stop] in whitespace then dec(stop);
    nextToken := copy(s,start,stop-start+1);
    delete(s,1,start+stop-1);
  end;
begin
  s := '    aaa    bbb	ccc   ';	// a test string
  writeln(nextToken(s));
  writeln(nextToken(s));
  writeln(nextToken(s));
end.

In doing it this way is a bit more obvious, at least for me. Gerhard

Gerhard Zintel
Faurecia Abgastechnik GmbH
Abt.: EGA
Fon.: +49 911 7610171
Fax.: +49 911 7610350
e-mail: GZintel<at>Stadeln.Faurecia.com

Reply by email

DONALD PEDDER
to ZINTEL Gerhard: here is just another approach. The function NextToken scans a string for the next token…
here is just another approach.

I'll have a look at that as well. Why doesn't the compiler have the ability to read a word? All of this extra code needed because I have to read words one character at a time! It would be the single most useful addition. I don't understand why compilers have no problems reading multi-digit numbers in one hit, but can't do the same with words.

thanks,
dp.

Reply by email

Florian Klaempfl
to DONALD PEDDER
DONALD PEDDER wrote 8 lines
>here is just another approach. I'll have a look at that as well. Why doesn't the compiler have the ability to read a word? All of this extra code needed because I have to read words one character at a time! It would be the single most useful addition. I don't understand why compilers have no problems reading multi-digit numbers in one hit, but can't do the same with words.

I guess for several reasons:
- it would require char set handling, only a minority uses only a-z as possible chars in words
- language dependend problems: e.g. is "it's" in english one or two words?
- hyphens
- ...

Reply by email

Marco van de Voort
to Florian Klaempfl
Show quoted text 12 lines
>>here is just another approach. > > > I'll have a look at that as well. Why doesn't the compiler have the > ability to read a word? All of this extra code needed because I have to > read words one character at a time! It would be the single most useful > addition. I don't understand why compilers have no problems reading > multi-digit numbers in one hit, but can't do the same with words. I guess for several reasons: - it would require char set handling, only a minority uses only a-z as possible chars in words

That means you define what makes up a word. You could also simply define what _separates_ a word ;-)

Reply by email

Laurent Cocea

Or you could wrap it around a Perl script. Perl is particularly good at parsing text and generating arrays from strings and vice-versa. And then you can call your Pascal-generated code from within the script using the array elements as arguments, liek this:

#!/usr/bin/perl -w

my @arguments;
my $arg;

open INF "<your_file.txt";
while (<INF>) {
chomp; # delete EOLN char
@arguments = split(/ /, $_); # generate arguments array from string }
close INF;

foreach $arg @args {
if ( $arg =~ m/[a-z][0-9]\_/i ) { # validate param string

    system("your_pascal-generated_binary_here $arg");
  } else {
    print "Skipped invalid argument $arg.\n";
  }

}

and then your Pascal code would use ParamStr() to read "command line" arguments, that is, the file name(s).

Reply by email

Florian Klaempfl
to Marco van de Voort: That means you define what makes up a word. You could also simply define what _separates_…
Marco van de Voort wrote 16 lines
>>>here is just another approach. >> >> >> I'll have a look at that as well. Why doesn't the compiler have the >>ability to read a word? All of this extra code needed because I have to >>read words one character at a time! It would be the single most useful >>addition. I don't understand why compilers have no problems reading >>multi-digit numbers in one hit, but can't do the same with words. > >I guess for several reasons: >- it would require char set handling, only a minority uses only a-z as >possible chars in words That means you define what makes up a word. You could also simply define what _separates_ a word ;-)

This isn't easy either, just consider the different quotation marks or questions marks (Spanish!) in different languages. It doesn't solve the problem, if you know the chars seperating words, you know the chars allowed in a word ;)

Reply by email

Alan Mead
to DONALD PEDDER: I'll have a look at that as well. Why doesn't the compiler have the ability to read a…

Donald,

What happens if the "Mighty Ducks" or the "White Sox"--or my favorite, "Eat at Joe's" play? The compiler reads strings just fine but you as the programmer need to understand data types. You also need to understand your problem. Parsing arbitrary and possibly inconsistent psuedo-English sentences is a very, very hard job and no compiler is going to get it right.

That said, I suggest you check out regular expressions. I believe I saw a regex support somewhere for FPC but I haven't used it with FPC. They are the technology for making many (but not all) simple parsing problems easy. In order to use regex's, you'll see that you first have to have a good grasp of how you want data parsed.

-Alan

--- DONALD PEDDER wrote 18 lines
> here is just another approach. I'll have a look at that as well. Why doesn't the compiler have the ability to read a word? All of this extra code needed because I have to read words one character at a time! It would be the single most useful addition. I don't understand why compilers have no problems reading multi-digit numbers in one hit, but can't do the same with words. thanks, dp. _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

__________________________________
Do you Yahoo!?
Free Pop-Up Blocker - Get it now
http://companion.yahoo.com/

Reply by email

Anton Tichawa
to Marco van de Voort: That means you define what makes up a word. You could also simply define what _separates_…
you wrote 14 lines
> >>here is just another approach. > > > > I'll have a look at that as well. Why doesn't the compiler have the > > ability to read a word? All of this extra code needed because I have to > > read words one character at a time! It would be the single most useful > > addition. I don't understand why compilers have no problems reading > > multi-digit numbers in one hit, but can't do the same with words. > > I guess for several reasons: > - it would require char set handling, only a minority uses only a-z as > possible chars in words That means you define what makes up a word. You could also simply define what _separates_ a word ;-)

But, as Murphy predicts, that very separator will sooner or later appear within a valid word.

@Donald: There ARE problems when reading numbers, e. g. "1000.0" is sometimes written as "1000,0", "1'000.0", "1,000.00" or even "1,000.--". It's a matter of negotiation: The more formal the text file, the easier it can be read by a program.

Anton.

----------

Ing. Anton Tichawa
Volkertstrasse 19 / 20
A-1020 Wien
phone: +43 1 218 97 59
email:

----------

"Adas Methode war, wie sich zeigen wird, Tagträume in offenbar korrekte Berechnungen einzuweben."

Doris Langley Moore: Ada, Countess of Lovelace (London 1977).

----------

Reply by email

DONALD PEDDER
to DONALD PEDDER: That was the missing piece of the puzzle. Thank you (and to Anton too)! dp.

Firstly, my current challenge, and then some responses to some other comments that were made.

> replace result:= by scanblack:= That was the missing piece of the puzzle. Thank you (and to Anton too)!

I've started actually writing my code now (I have a very busy life, so it sometimes takes a while to get back to things), and I am having issues in reading numbers. e.g. "49ers at Giants 16 13" (I know I didn't mention this to begin with, but I didn't think reading the score would be an issue, and it is).
When I've read everything up to the score (using scanblack/scanwhite), and then do "read(line,awayscore)" the program hangs (using read now, as I want to read the number and not a word). Experimentation showed me it was waiting for standard input, even though I've specified to read from the line I have scanned in. :-\
I know the result of scanblack is a string and not a number, so would I modify it to (hopefully) also read in numbers? Can I make it do both, or would I perhaps write another function to read numbers? I don't know if the latter would work, given that "read(line,...." isn't working.

What happens if the "Mighty Ducks" or the "White Sox"--or my favorite, "Eat at Joe's" play?

Not an issue as the only person who'll be using this program is me. :-) The input format is totally determined by me, and the code written accordingly (the input format is often even chosen to make the code easiest).

@Donald: There ARE problems when reading numbers, e. g. "1000.0" is sometimes written as "1000,0", "1'000.0", "1,000.00" or even "1,000.--".

Right, yet Pascal implements reading numbers as long as it is digits only. If you don't have digits only, then you know you'll have to write extra code to cope (perhaps reformatting the file first before processing, which is what I do with some of my stuff).
Why not have a similar approach with reading words? A word is either something that is entirely a-z,A-Z, or anything space-delimited. Anything outside of that case (whichever approach is taken), just like with numbers with non-digits in them, you write extra code, but at least when the format allows it you have an easy way to read words (something which I now have with this scanblack code, which makes life much easier than it was :-) ).

thanks,
DONALD.

E-mail -
BIG DON's Home-page - http://jedi.apana.org.au/~jims_son Pedder Passer Rating - http://jedi.apana.org.au/~jims_son/PPR AusNFL mailing-list - http://jedi.apana.org.au/mailman/listinfo/ausnfl

"What I always wanted is to be accepted, not understood" - MAN RAY

Reply by email

DONALD PEDDER
to DONALD PEDDER
When I've read everything up to the score (using scanblack/scanwhite), and then do "read(line,awayscore)" the program hangs (using read now, as I want to read the number and not a word).

P.S. "awayscore" IS defined as an integer, in case anyone is going to ask me if I've defined it correctly. "scanblack" returns a string, so I don't know how to return a number when required ("read(line,awayscore)" not working was un-expected - I guess maybe you can't read a number from a string, only from standard input/text file).

dp.

Reply by email

Anton Tichawa
to DONALD PEDDER: Firstly, my current challenge, and then some responses to some other comments that were…

Hello!

DONALD PEDDER wrote 9 lines
When I've read everything up to the score (using scanblack/scanwhite), and then do "read(line,awayscore)" the program hangs (using read now, as I want to read the number and not a word). Experimentation showed me it was waiting for standard input, even though I've specified to read from the line I have scanned in. :-\ I know the result of scanblack is a string and not a number, so would I modify it to (hopefully) also read in numbers? Can I make it do both, or would I perhaps write another function to read numbers? I don't know if the latter would work, given that "read(line,...." isn't working.

You can convert a string s, previously read in by scanblack, to a number:

var
  number: integer;
  code: integer;
begin
  // (read in string s)
  val(s, number, code);
  if code  0 then begin
    // error: the string s is not valid
  end;

(This is just from memory - I didn't test it.)

Ciao,

Anton.

Reply by email