• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

PERL GURU I NEED YOUR HELP?

Darkstar757

Diamond Member
Here the program specs
Write a Perl program to do the following:

1. Prompts for the complete path name, e.g. /home/shen/studentScores/class1, from the standard input (the terminal) of a file which is a text file. The first line in this file looks like the following:
Subjects- English Composition, Advanced Mathematics, Geography, History, Art
The first word must be Subjects and it is followed by a dash, as shown above. It is then followed by an arbitrary number of subject names separated by commas and possibly with arbitrary leading blanks in front of subject names. A subject name may have one or more words. In the above, five subject names were given.
After the first line, there are then an arbitrary number of lines of text such as the following three lines:
John Smith 77 82 49 79 95
Bill J. Bush, Jr. 87 89 93 40 80
Mary K. Bush 88 72 71 59 82
Each of the lines contains one or more words of a student's name. A student's name may not contain any digits but may have other characters as we know that may be in names. Following the student name, the numbers represent the scores the student obtained in subjects given in the first line, in that order.

2. Reads the complete path name which includes the file name and then picks up the file given in the pathname. It then reads that input file.

3. After reading the entire input file, for each subject, first prints on the standard output (the terminal) the subject title, then in each line a student name followed by the student's score in this subject. The students must be ordered in descending order of their scores in the subject. As an example, if the above sample input lines were the only ones in the file, then the program would print the following for the first two subjects:
English Composition
Mary K. Bush. 88
Bill J. Bush, Jr. 87
John Smith 77
Advanced Mathematics
Biil J. Bush, Jr. 89
John Smith 82
Mary K. Bush 72



My problem is I cant get the split function to work right.


I can get it to seperate the name but no each score of the student

here is my code

#!/usr/bin/perl -w




##print "Please Enter The Path Name of The Input File\n";

##print "Press Return Once You Have Entered The Path\n";

##chomp ($GRADES = <STDIN> );

open(GRADES, "hot.txt") or die "Can't open grades: $!\n";
while ($line = <GRADES>) {
#($student, $grade)=join('.',$line);
($student, $grade) = split(/([0123456789])/,$line);


$grades{$student} .= $grade ."";

print "$student\n";
print "$grade\n";
}

#/
#foreach $student (sort keys %grades) {
#$scores = 0;
#$total = 0;
#@grades = split(" ", $grades{$student});
#foreach $grade (@grades) {
#$total += $grade;
#$scores++;

#}


#$average = $total / $scores;
#print "$student: $grades{$student}\tAverage: $average\n";
#}



BTW this is not Home work and this is NOT FOR A GRADE.

I am doing this to further my programming skills which appear to be weaker than I thougt

🙁

Any help we be greatly appreciated

Thanks
Darkstar757
 
It's been a while since I coded in Perl last, but save everything to an array and split using the space character.

$line = 'John Smith 77 82 49 79 95';
@studentarr = split(/ /,$line);

$studentarr[0] should be the first name.
$studentarr[1] should be the last name.
$studentarr[2] should the student's first grade.
$studentarr[6] should be the student's last grade.
 
Originally posted by: yllus
It's been a while since I coded in Perl last, but save everything to an array and split using the space character.

$line = 'John Smith 77 82 49 79 95';
@studentarr = split(/ /,$line);

$studentarr[0] should be the first name.
$studentarr[1] should be the last name.
$studentarr[2] should the student's first grade.
$studentarr[6] should be the student's last grade.

can't remember the syntax, but that's what i did
 
My syntax might be slightly off too, but I think I have everything in my previous post right. You could go the harder route (the one you originally picked) and split based on where the last alphabetic character was placed, then use $` and $' to put the two halves in the proper variable holders. Why bother really.
 
Originally posted by: yllus
It's been a while since I coded in Perl last, but save everything to an array and split using the space character.

$line = 'John Smith 77 82 49 79 95';
@studentarr = split(/ /,$line);

$studentarr[0] should be the first name.
$studentarr[1] should be the last name.
$studentarr[2] should the student's first grade.
$studentarr[6] should be the student's last grade.

the only problem is that there is no standard format for the students' names. there may be 3 parts to it (eg - john doe, jr. 88 87 86 85).

i think you'll have to loop through @studenarr until the element has a number, then just put the rest of the elements in a separate list.

foreach $item @studentarr{
if($item =~ /[0-9]/){ push(@grades,$item); }
}

after this @grades should contain the grades in the proper order. someone please check my syntax for push, i don't have my perl reference around.

the code from the original OP looks like it is splitting the line into 2 parts, the student's name and then the list of grades afterwards. i think.

EDIT: i was incorrect about what the OP's code will do. i think it ends up returning [full name, space, space, space, etc.] since you're splitting using the numbers as the delimiter as opposed to using the spaces as the delimiter.
 
Originally posted by: yllus
It's been a while since I coded in Perl last, but save everything to an array and split using the space character.

$line = 'John Smith 77 82 49 79 95';
@studentarr = split(/ /,$line);

$studentarr[0] should be the first name.
$studentarr[1] should be the last name.
$studentarr[2] should the student's first grade.
$studentarr[6] should be the student's last grade.

see but i want the first and last name in one record of the array.


also the first and last name can have a . or , after the middle inital

the other problem is with doing it that way i will have values that dont match the students name.

 
Anyone else read PERU GURL instead of PERL GURU in the title of this thread?

It's not my fault, it's all the YAGT threads on here.. lol. !!Me losin Me Mind!!
 
Originally posted by: Darkstar757
Originally posted by: yllus
It's been a while since I coded in Perl last, but save everything to an array and split using the space character.

$line = 'John Smith 77 82 49 79 95';
@studentarr = split(/ /,$line);

$studentarr[0] should be the first name.
$studentarr[1] should be the last name.
$studentarr[2] should the student's first grade.
$studentarr[6] should be the student's last grade.

see but i want the first and last name in one record of the array.


also the first and last name can have a . or , after the middle inital

the other problem is with doing it that way i will have values that dont match the students name.

that's ok. just do this:

@studentarr = split(/ /,$line);

foreach $item @studentarr{

if ( $item =~ /[0-9] ) {

push @grades, $item;

} else {

push @name, $item;

}

afterwards, i think you'll have 1 item in @name which should be the name and X items in @grades where X = number of grades.
 
$line = "john doe, jr. 88 87 86 85 84";

@studentarr = split (/ /,$line);

print "@studentarr\n";

foreach $item (@studentarr){
if ($item =~ /[0-9]/) {
push @grades, $item;
}else{
push @name, $item;
}
}

EDIT: just tried it out, looks correct. sorry for the bad formatting.
 
To split the sutdent name lines, assume that "$line" cantains the entire thing:

$line =~ s/^(\D+)//;
$name = $1;
@grades = split /\s+/, $line;

 
Originally posted by: blackdogdeek
$line = "john doe, jr. 88 87 86 85 84";

@studentarr = split (/ /,$line);

print "@studentarr\n";

foreach $item (@studentarr){
if ($item =~ /[0-9]/) {
push @grades, $item;
}else{
push @name, $item;
}
}

EDIT: just tried it out, looks correct. sorry for the bad formatting.

Can't modify constant item in scalar assignment at tes
doe, jr. 88 87 86 85 84";"
Execution of test.pl aborted due to compilation errors

is the error im getting


 
Originally posted by: notfred
To split the sutdent name lines, assume that "$line" cantains the entire thing:

$line =~ s/^(\D+)//;
$name = $1;
@grades = split /\s+/, $line;

hey fred can you explain what each of those symbols are doing

cause i think that part of my hang up

 
Originally posted by: notfred
To split the sutdent name lines, assume that "$line" cantains the entire thing:

$line =~ s/^(\D+)//;
$name = $1;
@grades = split /\s+/, $line;

doh. this solution is more elegant.

🙁
 
Originally posted by: blackdogdeek
$line = "john doe, jr. 88 87 86 85 84";

@studentarr = split (/ /,$line);

print "@studentarr\n";

foreach $item (@studentarr){
if ($item =~ /[0-9]/) {
push @grades, $item;
}else{
push @name, $item;
}
}

EDIT: just tried it out, looks correct. sorry for the bad formatting.


ok

i got it to work now to try it again



 
Originally posted by: Darkstar757
Originally posted by: notfred
To split the sutdent name lines, assume that "$line" cantains the entire thing:

$line =~ s/^(\D+)//;
$name = $1;
@grades = split /\s+/, $line;

hey fred can you explain what each of those symbols are doing

cause i think that part of my hang up

iirc, this does the following:

substitutes(s/) everthing at the beginning of the line (^) that is is not a number(\D), there may be more than one thing(+), with nothing (//), and capture it into $name($name = $1). EDIT: $1 is the first returned value in the substitution line.

then it just splits the rest with 1 or more spaces as the delimiter.
 
Try this.

my @test = ("John Smith 77 82 49 79 95",
"Bill J. Bush, Jr. 87 89 93 40 100",
"Mary K. Bush 88 72 71 59 82");


for (@test){
my ($name,$first,$second,$third,$fourth,$fifth) = $_ =~ /^(.+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/;

print "$name $first $second $third $fourth $fifth\n";
}

forgot a space between name and first number. hehehe
 
Originally posted by: Darkstar757
Originally posted by: notfred
To split the sutdent name lines, assume that "$line" cantains the entire thing:

$line =~ s/^(\D+)//;
$name = $1;
@grades = split /\s+/, $line;

hey fred can you explain what each of those symbols are doing

cause i think that part of my hang up

The first line is a substitution, it matches \D+ at the beginning of a string. \D is a character class for everything that is not a number, it's equivelent to [^1234567890]. The parentheses are used to create the $1 variable, and the matching part of the string (everything up unti lthe first digit) is replaced with nothing (effectively removed fro mthe string).

$name = $1 creates a new $name variable from the temporary $1 variable we created with our parentheses in the regex.

@grades = split.... splits the remainder of the line at whitespace.
 
here is the txt file im using

Noel 25 89 109
Ben 76 56
Clementine 49 56
Norm 66 64
Chris 92 34
Chris 12
Bill J. Bush, Jr. 87



open(GRADES, "hot.txt") or die "Can't open grades: $!\n";
while ($line = <GRADES>) {



@studentarr = split (/ /,$line);

print "@studentarr\n";

foreach $item (@studentarr){
if ($item =~ /[0-9]/) {
push @grades, $item;
}else{
push @name, $item;
}
}




foreach $grade (@grades) {
$total += $grade;
$scores++;

}


$average = $total / $scores;
print "$student: $grades{$student}\tAverage: $average\n";

}


ok

now for some reason Im not getting the correct adverages anymore

Noel 25 89 109

: Average: 74.3333333333333
Ben 76 56

: Average: 72.25
Clementine 49 56

: Average: 69.2
Norm 66 64

: Average: 67.8333333333333
Chris 92 34

: Average: 66.9714285714286
Chris 12

: Average: 65.3617021276596
Bill J. Bush, Jr. 87
: Average: 64.7833333333333



 
lol, I didn't know you could have n number of grades behind the names. notfred solution is good. BTW, you have to reset your total and score variables for each student. Those varibles will just get bigger and bigger as you went thru the file. 😀
 
Just for the hell of it, I beleive this is the entire solution to the problem in the first post. I didn't see anything about averages in there, so I left them out.

EDIT: Added average support

#!/usr/bin/perl

use strict;

# Get filename and list of subjects.
print "Enter filename: ";
my $filename = <>;
open FILE, "$filename";
my $subjects = <FILE>;
chomp $subjects;
$subjects =~ s/Subjects-\s*//;
$subjects =~ s/\s*,\s*/,/g;
my @subjects = split /,/, $subjects;
@subjects = sort @subjects;

# Create a hash for averages.
my %averages;

# Initialize an array of hashes
my @grades;
for my $ii(0..$#subjects){
my %newhash;
push @grades, \%newhash;
}

# Process each student
while(<FILE>){
# Get name
$_ =~ s/^(\D+)//;
my $name = $1;

# Get scores
my @scores = split /\s+/, $_;

# Figure out this student's average score.
my $total = 0;
foreach my $value(@scores){$total += $value;}
$averages{$name} = $total/@scores;

# For each subject, insert the score into the proper hash in @grades
for my $subject(0..$#subjects){
${$grades[$subject]}{$scores[$subject]} = $name;
}
}

# Print each subject
foreach my $subject(0..$#subjects){
print "$subjects[$subject]\n";
foreach my $score(reverse sort keys %{$grades[$subject]}){
print ${$grades[$subject]}{$score}, ": $score\n";
}
print "\n";
}

# Display averages
print "AVERAGE SCORES\n";
foreach my $key(keys %averages){
print "$key: $averages{$key}\n";
}
 
Back
Top