0

I have this sample text which I would like to access one of the multiple lines from a single array element.

Student 1:
Math 83
Chemistry 60
Physics 75

Student 2:
Math 69
Chemistry 76
Physics 73
Art A-

My script for storing multiple lines to a single array element is as following:

use strict;
use warnings;

open my $fh, '<', 'Text1' or die "Could not open file to read:$!";
my $file = do { local $/; <$fh> };
my @a = split /\n\n/, $file;
close $fh;

print "First array element is $a[0]\n";
print "Second array element is $a[1]\n";

The output is

First array element is Student 1:
Math 83
Chemistry 60
Physics 75
Second array element is Student 2:
Math 69
Chemistry 76
Physics 73
Art A-

Is there a better way for me to access and grab one of the multiple lines in first or 2nd element of the array for further usage? i.e, I need Math score from each student. Here is what I come up so far, to join the first element of the array and split them again. Thanks in advance.

use strict;
use warnings;

open my $fh, '<', 'Text1' or die "Could not open file to read:$!";
my $file = do { local $/; <$fh> };
my @a = split /\n\n/, $file;
close $fh;

print "First array element is $a[0]\n";
print "Second array element is $a[1]\n";

my $str=join('',$a[0]);
my @score1 = split('\n',$str);
$str=join('',$a[1]);
my @score2 = split('\n',$str);

print "Student 1 : $score1[1]\n";
print "Student 2 : $score2[1]\n";

2 Answers 2

3

Your read and split can be simplified to using readline's paragraph mode:

my @student = do { local $/ = ""; <$fh> };

I would be inclined to break each student up into a hash:

my @student = map {
    my ($student, $scores) = /\A(.*):\n(.*)/s;
    {
        'Name' => $student,
        split ' ', $scores
    }
} do { local $/ = ""; <$fh> };

for my $student_number (0..1) {
    print "Name: $student[$student_number]{Name}  Math Score: $student[$student_number]{Math}\n";
}

If there is no blank line between students:

my @student;
my $current_student;
while ( my $line = <$fh> ) {
    if ( my ($name) = $line =~ /^(.*):/ ) {
        $current_student = { 'Name' => $name };
        $line =~ s/^.*://;
        push @student, $current_student;
    }
    my @scores = split ' ', $line;
    while ( my ($subject, $score) = splice(@scores, 0, 2) ) {
        $current_student->{$subject} = $score;
    }
}

(A subject has to be on the same line as its score.)

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! This is a neat output for display. Would you allow me for another question? What if there is no newline between the two student's data? How can I split the data?
how would you tell when a new student starts? the colon?
Is it possible? for colon?
3

Instead of 'slurping' the entire file, you could read in one 'paragraph' at a time by setting $/ to "". I would have used a hash instead of @score1 and @score2. Then you could address the sought math score by using Math as a key. It would look something like this-

#!/usr/bin/perl
use strict;
use warnings;

my @grades;

{
    local $/ = "";
    while (<DATA>) {
        push @grades, { split };
    }   
}

for my $href (@grades) {
    print "student: $href->{Student} Math: $href->{Math}\n";    
}

Output-

student: 1: Math: 83
student: 2: Math: 69

1 Comment

Thanks. It works fine. Another question if you allow me, what if there is no newline between the two student's data? Student 1: Math 83 Chemistry 60 Physics 75 Student 2: Math 69 Chemistry 76 Physics 73 Art A- How would I have split it? I do not wish to use splice operator since the subjects might be different for each student.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.