Perl read a file and an array and find common words - arrays

This is kind of a small issue and I hope you are able to help me. My code is probably rubbish. For an example, I have a file in which the only statement is John is the uncle of Sam. My Perl script should copy the file contents into an array. User should be able to input different names and search if those names are mentioned in the file. There should be an array with relationships like "uncle aunt, mother, father etc" in the program.
#use warnings;
use Array::Utils qw(:all);
print "Please enter the name of the file\n";
my $c = <STDIN>;
open(NEW,$c) or die "The file cannot be opened";
#d = <NEW>;
print #d, "\n";
#g = qw(aunt uncle father);
chomp #d;
chomp #g;
my $e;
my $f;
print "Please enter the name of the first person\n";
my $a = <STDIN>;
print "Please enter the name of the second person\n";
my $b = <STDIN>;
my #isect = intersect(#g, #d);
print #isect;
foreach(#d)
{
if ($a == $_)
{
$e = $a;
}
else
{
print "The first person is not mentioned in the article";
exit();
}
if ($b == $_)
{
$f = $b;
}
else
{
print "The second person is not mentioned in the article";
exit();
}
}
print $e;
print $f;
close(NEW);
This is something that I have done so far, the intersection is not giving the word uncle which is the word common in both arrays. The program is taking any random name and printing them. It is not saying that the name doesn't exist in the file when I enter a different name other than John and Sam

There are several problems:
You do not chomp $c. The filename contains a newline at the end.
You use the 2-argument form of open, but do not test the second argument. This is a security problem: do you know what happens if the user input contains > or |?
You use == to compare strings. String equality is tested with eq, though, == tests numbers.
Moreover, you do not want to know whether "Sam" equals to "John is the uncle of Sam". You want to know whether it is a part of it. You might need to use index or regular expressions to find out.
Do not use $a as the name of a variable, it is special (see perlvar).

Do not try to compare strings with ==! Use eq (equals) instead. Also you didnt chomp your input $a$b`. I think this is what you're trying to do:
#!/usr/bin/perl
use strict;
use warnings;
print "Please enter the name of the file\n";
my $c = <STDIN>;
open(NEW,$c) or die "The file cannot be opened";
my #d = <NEW>;
chomp #d;
my $e;
my $f;
print "Please enter the name of the first person\n";
my $aa = <STDIN>;
print "Please enter the name of the second person\n";
my $bb = <STDIN>;
chomp $aa;
chomp $bb;
my $pattern_a = quotemeta $aa;
my $pattern_b = quotemeta $bb;
foreach (#d){
if ($_ =~ /$pattern_a/){
$e = $aa;
}
elsif ($_ =~ /$pattern_b/){
$f = $bb;
}
}
close(NEW);
unless ($e){
print "First person not mentionend\n";
}
unless ($f){
print "Second person not mentioned\n";
}

Related

Updated file strings words together

My script works, except when I append the file: it bunches my words into one string like so:
Joe Smo45MaleSingle
Originally, in the text file, they are in a column. I want the appended file to stay in a column.
#!/usr/bin/perl
use strict;
use warnings;
use File::Slurp;
my #array1 = ("Full Name:", "Age:", "Gender:", "Marital Status:");
my #array2 = read_file("empdata.txt", chomp => 1);
print "$array1[0] $array2[0]\n";
print "$array1[1] $array2[1]\n";
print "$array1[2] $array2[2]\n";
print "$array1[3] $array2[3]\n";
print "Do you want to change the age? (y or n) :";
chomp(my $answer = <STDIN>);
if ($answer eq "y") {
print "What is the new age? :";
chomp(my $age = <STDIN>);
$array2[1] = $age;
write_file("empdata.txt",#array2);
print "Do you want to change marital status? (y or n) :";
chomp(my $answer = <STDIN>);
if ($answer eq "y") {
print "What is the new marital status? :";
chomp(my $status = <STDIN>);
$array2[3] = $status;
write_file("empdata.txt",#array2);
}
} else {
print "Do you want to change marital status? (y or n) :";
chomp(my $answer = <STDIN>);
if ($answer eq "y") {
print "What is the new marital status? :";
chomp(my $status = <STDIN>);
$array2[3] = $status;
write_file("empdata.txt",#array2);
}
}
close || die "could not close file";
I'm guessing, because you haven't shown us your input data. But I think you're saying that your input file looks like this:
Joe Smo
45
Male
Single
And, after running your program, you end up with this:
Joe Smo45MaleSingle
When you read the file, you use the chomp => 1 option to read_file(). That removes newlines from the end of the lines in the file. But write_file() doesn't have an unchomp option to replace the newlines.
The quickest, dirtiest, fix is to stop removing the newlines. You'll want to remove the chomp => 1 option from read_file() and also stop calling chomp() on the new $status values as you read them in. You can also remove the "\n" from the lines where you are printing the original records (as they will have a newline attached).
However, I'd caution you against using File::Slurp. It has some problems with UTF8 data that are likely to burn you in the future. I'd recommend Path::Tiny (which has slurp() and spew() methods) in its place.
But, really, it looks like you're writing a database. So why not use a database?

Perl: How to reference to an array?

I have a program here that will allow user to enter in words that will be used as filenames later on. The user's input is inserted into an array. I then create a simple menu asking what the user wants to do with the "filename": create, reame, copy, and delete. Using subroutines, I believe I've successfully executed the code. However, I am having trouble trying to reference the array element.
In short, how do I create, rename, copy, and delete the filenames that are saved in the array? The issues I cant resolve are asterisked
#!/usr/bin/perl
use strict;
use warnings;
use File::Copy qw/copy/;
my $new;
my $old;
my $file;
print "Enter number of lines\n";
chomp(my $n = <STDIN>);
my #lines;
print "Enter some words!\n";
for (1..$n) {
chomp(my $input = <STDIN>);
#will add the user input at the beginning of the array
push #lines, $input;
}
print "#lines\n";
#create a menu
my $in = '';
print "1. Create\n2. Rename\n3. Copy\n4. Delete\n5. Quit\n";
while ($in ne "quit")
{
print "\nEnter the your choice:\n";
chomp($in = <STDIN>);
print "For which file do you want to $in?\n";
print "#lines\n";
**#I need to reference the array here***********************
if ($in eq "create") {
***How to create the file that the user inputted?*****************
&createFile;
print "\nFile has been created\n";
}
elsif ($in eq "rename") {
#print "Enter the old name\n";
# chomp($old = <STDIN>);
#*********refer to array of FILES*********************
print "Enter the new name for this file!\n";
chomp($new = <STDIN>);
&renameFile;
print "File has successfully been renamed.";
}
elsif ($in eq "copy") {
#********file and array refering***************************
&copyFile;
print "Hopefully, the file has beed copied!";
}
elsif ($in eq "delete") {
#******refer to file from user*******************
&deleteFile;
print "Deleted";
}
}
#create subroutine
sub createFile {
open('>' .*****issue here too**) or die "\nCannot create";
}
sub renameFile {
rename ($old, $new);
}
sub copyFile {
copy $old, $new;
}
sub deleteFile {
#unlink *****************************
}
First line is $line[0], second is $line[1] and so on...
You can get user choice like this:
$line[$in]
About how to refer to perl data structures see here
$lines[0]; #First line
$lines[1]; #Second line
$array = \#lines; # Get reference to the list of lines
$array->[0]; #First line
$array->[1]; #Second line
to create file and put data into just use:
open $fh, '>filename';
print $fh #lines;
print $fh #$array; # ... or same for reference
Notice lack of coma after $fh

What is the proper way to search array using Smart Match?

I'm new to programming much less Perl; I'm having difficulty with searching an array I've made from an external text file. I'm looking for a simple way to check if the user entry is located in the array. I've used the Smart Match function before but never in an "if" statement and can't seem to get it to work. Am I implementing this function wrong, or is there an easier way to check if the user's string is in the array?
#!/usr/bin/perl
use 5.010;
#Inventory editing script - Jason Black
#-------------------------------------------------------------------------------
print "1. Add Items\n";
print "2. Search Items\n";
print "Please enter your choice: ";
chomp ($userChoice = <STDIN>); #Stores user input in $userChoice
if($userChoice == 1){
$message = "Please enter in format 'code|title|price|item-count'\n";
&ChoiceOne;
}
elsif($userChoice == 2){
$message = "Enter search terms\n";
&ChoiceTwo;
}
sub ChoiceOne{
print "$message\n";
chomp($userAddition = <STDIN>); #Stores input in $userAddition
$string1 = "$userAddition";
open (FILE, "FinalProjData.txt") or die ("File not found"); #"FILE" can be named anything
#array = <FILE>;
if ( /$string1/ ~~ #array){
print "This entry already exists. Would you like to replace? Y/N \n";
chomp($userDecision = <STDIN>); #Stores input in $userDecision
if ($userDecision eq "Y"){
$string1 =~ s/$userAddition/$userAddition/ig;
print "Item has been overwritten\n";}
elsif($userDecision eq "N"){
print FILE "$string1\n";
print "Entry has been added to end of file.\n";}
else{
print "Invalid Input";
exit;}
}
else {
print FILE "$string1\n";
print "Item has been added.\n";}
close(FILE);
exit;
}#end sub ChoiceOne
sub ChoiceTwo{
print "$message\n";
}
If you want to avoid using smartmatch alltogether:
if ( grep { /$string1/ } #array ) {
To actually match the $string1, however, it needs to be escaped, so that | doesn't mean or:
if ( grep { /\Q$string\E/ } #array ) {
or just a simple string compare:
if ( grep { $_ eq $string } #array ) {

Building a Perl program to acess a set of data

I have to write a Perl program that is able to read the social security baby names for a specific year, and have a person be able to enter a name, and be told weather it is male or female, how many people were born with that name, and where it falls in rank.
So far I have been able to separate the data into two separate arrays based on gender, but have to no idea where to go from here.
#!/usr/local/bin/perl
use strict;
use warnings;
open (FILE, "ssbn1898.txt");
print <FILE>;
close (FILE);
my #M_array;
my #F_array;
open (my $input, "<", 'ssbn1898.txt');
while ( <$input> ) {
chomp;
my ( $name, $gender ) = split ( /,/ );
if ( $gender = "M" ) {
push ( #M_array, $name );
}
else {
push ( #F_array, $name );
}
}
close ( $input );
print 'M: ' . join("\t", #M_array) . "\n";
print 'F: ' . join("\t", #F_array) . "\n";
http://www.ssa.gov/cgi-bin/popularnames.cgi
This is the data I am working with.
So far you have 2 arrays for each gender. Now the pending tasks are
Input: Allow users to input a name
Output: Male or Female
Output: Number of people with that name
To take input from user you could do
my $userinput = <STDIN>;
Then you might need to chomp the $userinput and then check whether the $userinput is in array 1 or array 2. For that you will have to use grep or loops. Doing that you'd be able to find whether name belongs to array with Male names or Females.
if (grep /$userinput/, #male_names) {
print "found $userinput in male list\n";
}
Using loop you could do something like below to find total number of people with that name:
foreach (#male_names){
$counter++ if $userinput eq $_;
}
PS: grep returns list, so if you use a scalar you could find number of matches, so you don't have to go for loops.
#!/usr/bin/perl
use strict;
use warnings;
my #male_names = qw(Raj Rohan John Jim Tony Raj Rohan Jim Jim);
my #female_names = qw(Natasha Neha Neha Jasmine Rita Rosy);
my $matches;
my $userinput = <STDIN>;
chomp ($userinput);
if ( $matches = grep /$userinput/, #male_names ) {
print "found $userinput in male list, count is $matches \n";
}
elsif ( $matches = grep /$userinput/, #female_names ) {
print "found $userinput in female list, count is $matches \n";
}
else{
print "Did not find name";
}

printing arrays to text file (v2)

yesterday i asked this question and got many helpful replies, hoping the same will be true today. Here is my revised script.
#! /usr/bin/perl
use strict;
use warnings;
my $line;
my #array;
my $print;
open (OUT , ">","output.txt")or die "cant open: $!";
while ($line = <>){
chomp($line);
push(#array, $line);
if(#array == 250){
$print = print "[", join(",",#array), "]", "\n";
print OUT $print;
#array = []
}
}
Originally i simply stated that i need to print out the first 250 elements of an array to a text file, and that this array was built from standard input. What i didnt state is that the input, from which the array is built, may consist of several thousand lines. The reason for creating an array from this input is so that i can limit the size of the array to 250 entities, and then print the array as a formatted string. I then need to flush the array and resume building at what will become the 251st line of the input, and continue doing this process for the remainder of the input. Lets say the input is 5k lines, i want my output to be a text file containing the original 5k lines of input, but divided into strings made up of 250 array entities.
Currently the script is just printing the array to the screen and inside "ouput.txt" is a single line reading: 1111111.
$print = print "[", join(",",#array), "]", "\n";
print OUT $print;
Here you are assigning the return value of print to $print, which is 1, because the printing is successful. What you want to do is this:
print OUT "[", join(",",#array), "]", "\n";
Here's another option which just slightly modifies your script:
use strict;
use warnings;
my #array;
local $" = ',';
while (<>) {
chomp;
push #array, $_;
if ( #array == 250 ) {
print "[#array]\n";
undef #array;
}
}
Usage: perl script.pl Infile [>outFile]
The last, optional parameter directs output to a file.
The variable $" is holds Perl's list separator that's applied to an interpolated array, so join's not needed here.
Hope this helps!
#! /usr/bin/perl
use strict;
use warnings;
my $line;
my #array;
my $print;
open (OUT , ">","moloch_chunker_output.txt")or die "cant open: $!";
while ($line = <>){
chomp($line);
push(#array, $line);
if(#array == 250){
print OUT "[", join(",",#array), "]", "\n";
#array = ();
}
}
Thank you davs, that fixed it.

Resources