473,699 Members | 2,364 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

New to Perl and have basic array question

3 New Member
I just started teaching myself Perl a couple days ago, and am looking forward to what this will give me for my Linux administration skills. Any help on this will be appreciated.

I ran into a problem in writing a simple script for searching for an entry in a file, then erasing the entire line. I know this can be done with grep -v in the Linux command line, but I felt I needed the practice.

The problem I'm having is that the script works, but when it finds and erases a match, it ignores the next match. I've already shown this to a friend who said it's a "weird way" to go about it, but he doesn't work much with arrays.

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. open(INFILE, "test") or die "Can't open file.";
  7. my @array = <INFILE>;
  8. close(INFILE);
  9.  
  10. my $number_removed = 0;
  11. my $loops = 0; #Used to tell splice() what part of the array to remove
  12.  
  13. foreach my $l (@array) {
  14.     if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
  15.         splice(@array, $loops, 1); #Remove the part of the array that's
  16.         $number_removed += 1; #being searched
  17.     }
  18.     $loops += 1; #Each time a line is searched increment this value to
  19. } #...allow splice to remove the correct line
  20.  
  21. open(OUTFILE, ">test_result"); #Print the remaining @array to a file
  22. print OUTFILE @array;
  23. close(OUTFILE);
  24.  
  25. print "$number_removed entries were removed.\n"
  26.  
Jun 6 '07 #1
5 1869
miller
1,089 Recognized Expert Top Contributor
Greetings and welcome to perl.

Yes, your method of implementation is more difficult than it needs to be, but this will make for good practice. The main bug with your current implementation is the fact that you should not be incrementing the index when you remove an element from the array, becuase you just reduced the size by one. So here is your current code so fixed:

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. open(INFILE, "test") or die "Can't open test: $!";
  7. my @array = <INFILE>;
  8. close(INFILE);
  9.  
  10. my $number_removed = 0;
  11. my $index = 0; #Used to tell splice() what part of the array to remove
  12.  
  13. foreach my $l (@array) {
  14.     if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
  15.         splice(@array, $index, 1); #Remove the part of the array that's
  16.         $number_removed++; #being searched
  17.     } else {
  18.         $index++; #Each time a line is searched increment this value to
  19.     }
  20. } #...allow splice to remove the correct line
  21.  
  22. # Print the remaining @array to a file
  23. open(OUTFILE, ">test_result") or die "Can't open test_result: $!";
  24. print OUTFILE @array;
  25. close(OUTFILE);
  26.  
  27. print "$number_removed entries were removed.\n"
  28.  
However, there are two methods for file manipulation that you should probably learn for this. First of all, your entire loop procedure could be simplified by the use of the grep perl function.

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. open(INFILE, "test") or die "Can't open test: $!";
  7. my @array = <INFILE>;
  8. close(INFILE);
  9.  
  10. my $oldsize = @array;
  11.  
  12. # Remove all noted lines.
  13. @array = grep {!/SHOREWALL/i} @array;
  14.  
  15. my $number_removed = $oldsize - @array;
  16.  
  17. # Print the remaining @array to a file
  18. open(OUTFILE, ">test_result") or die "Can't open test_result: $!";
  19. print OUTFILE @array;
  20. close(OUTFILE);
  21.  
  22. print "$number_removed entries were removed.\n"
  23.  
Also, you can take advantage of the Tie::File core module in order to simply edit the file in place. The use of your for loop and use of splice then comes in handy in a real way.

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2.  
  3. use Tie::File;
  4.  
  5. use strict;
  6. use warnings;
  7.  
  8. tie my @array, 'Tie::File', "test" or die "Can't open test: $!";
  9.  
  10. my $number_removed = 0;
  11.  
  12. for (my $index = 0; $index <= $#array;) {
  13.     if ($array[$index] =~ /SHOREWALL/i) {
  14.         splice @array, $index, 1;
  15.         $number_removed++;
  16.     } else {
  17.         $index++;
  18.     }
  19. }
  20.  
  21. untie @array;
  22.  
Also, as a general rule, whenever you find that you're keeping track of the index of an array, then you should use a for statement instead of a foreach. If you're just accessing the elements, then foreach is the way to go.

There are other methods to accomplish what you're trying to do, but these are two good ones to get you started on your quest for more tools.

- Miller
Jun 6 '07 #2
svancouw
3 New Member
Miller, thank you very much for your corrections and suggestions. I will look at this closely and see what I can learn from it, and will use these techniques in more practice programs.
Jun 7 '07 #3
miller
1,089 Recognized Expert Top Contributor
Your welcome. Good luck.

- Miller
Jun 7 '07 #4
svancouw
3 New Member
Miller, while I am sure your suggestion will be of great use, the corrected code you gave me still has the same symptom of skipping entries in the file. I created a new pl script and pasted the contents from your post.

In your response, you said that I shouldn't be incrementing the index, but does not your code do this as well? I don't suppose you have any other thoughts on this matter?

These are the contents of the file "test" that I used, with most lines numbered that helped me see what was going wrong.

SHOREWALL rocks
SHOREWALL SUCKS
George
Steve
3
4SHOREWALL
5SHOREWALL
6
7SHOREWALL
8SHOREWALL
9SHOREWALL
10
11SHOREWALL
12SHOREWALL
13SHOREWALL
14SHOREWALL
15
16SHOREWALL
17hi there bob
18SHOREWALL
19SHOREWALL
20hi
21there
22SHOREWALL
23bob
24go
25 away
26SHOREWALL
27i
28do
29not
30like
31mysteries
32


-Sean
Jun 7 '07 #5
miller
1,089 Recognized Expert Top Contributor
Greetings Sean,

You're right. The first code that I gave you doesn't work. The question is, can you figure out why? I know why, but the best way for you to learn would be to work through the steps. Let's see if I can help you:

Try adding some debugging statements to the script and see what results. Something like this is rather illuminating. It outputs the current

Expand|Select|Wrap|Line Numbers
  1. foreach my $l (@arraymirror) {
  2.     print "$index - $l";
  3.     if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
  4.         splice(@array, $index, 1); #Remove the part of the array that's
  5.         $number_removed++; #being searched
  6.         print "     Removed\n";
  7.     } else {
  8.         $index++; #Each time a line is searched increment this value to
  9.     }
  10. } #...allow splice to remove the correct line
  11.  
After viewing the output we see that some of the entries in the @array are being skipped. Immediately we ask why this is? I think we can presume that it has something to do with the fact that we are modifying the array that we are looping on. We could check perdoc for answers about foreach. However, it's try something else. How about just replacing the array that we're looping on with a duplicate array.

Expand|Select|Wrap|Line Numbers
  1. my @staticarray = @array;
  2. foreach my $l (@staticarray) {
  3.     print "$index - $l";
  4.     if ($l =~ /SHOREWALL/i) { #Search for the shorewall string
  5.         splice(@array, $index, 1); #Remove the part of the array that's
  6.         $number_removed++; #being searched
  7.         print "     Removed\n";
  8.     } else {
  9.         $index++; #Each time a line is searched increment this value to
  10.     }
  11. } #...allow splice to remove the correct line
  12.  
Ta-da! It works. Now obviously this is rather annoying. So now I go back to my earlier advice that I gave you. The other two methods of implementation do in fact work, and it's the third one that you should take note of. I told you that if you're ever accessing the index of an array, then you should just loop through the array by index instead of using foreach. The exact code that I provided that will can be used and will work. That gives us this

Expand|Select|Wrap|Line Numbers
  1. use strict;
  2. use warnings;
  3.  
  4. open(INFILE, "test") or die "Can't open test: $!";
  5. my @array = <INFILE>;
  6. close(INFILE);
  7.  
  8. my $number_removed = 0;
  9.  
  10. for (my $index = 0; $index <= $#array;) {
  11.     if ($array[$index] =~ /SHOREWALL/i) {
  12.         splice @array, $index, 1;
  13.         $number_removed++;
  14.     } else {
  15.         $index++;
  16.     }
  17. }
  18.  
  19. # Print the remaining @array to a file
  20. open(OUTFILE, ">test_result") or die "Can't open test_result: $!";
  21. print OUTFILE @array;
  22. close(OUTFILE);
  23.  
  24. print "$number_removed entries were removed.\n"
  25.  
Output:
Expand|Select|Wrap|Line Numbers
  1. >perl scratch.pl
  2. 16 entries were removed.
  3.  
Good luck in your further studies.
- Miller
Jun 7 '07 #6

Sign in to post your reply or Sign up for a free account.

Similar topics

1
19349
by: sam | last post by:
I have a function writen in Perl that takes a name-value list (array) as argument and returns a name-value list (array). My question is: How to call this function from PHP and get the returned name-value list in PHP variable? Thanks.
14
2570
by: Xah Lee | last post by:
Just bumped into another irresponsibility in perl. the crime in question this time is the module File::Basename. Reproduction: 1. create a directory containing a file of this name: "cdrom.html". 2. "use File::Basename;", with the line: ($name,$path,$suffix) = fileparse($File::Find::name, ('.html', '.m'));
31
4792
by: surfunbear | last post by:
I've read some posts on Perl versus Python and studied a bit of my Python book. I'm a software engineer, familiar with C++ objected oriented development, but have been using Perl because it is great for pattern matching, text processing, and automated testing. Our company is really fixated on risk managnemt and the only way I can do enough testing without working overtime (which some people have ended up doing) is by automating my...
0
2211
by: dohnut | last post by:
Here's one for some bored problem solver :) I ran across this earlier today and fixed it, but don't exactly know why. (that usually only happens in C :) I'm using Perl version 5.8.0 btw. Ok, let's start here: I end up with an array that comes from a fetchrow_array() call to MySQL. I return the array to a function.
0
3004
by: Vsevolod (Simon) Ilyushchenko | last post by:
Hi, I have succesfully connected from a dotnet client on Windows to a Perl service and was able to send basic data types and arrays back to Windows. However, I tried sending a two-dimensional array, and something went wrong. This is how I define the service in the client proxy:
0
9739
by: Kirt Loki Dankmyer | last post by:
So, I download the latest "stable" tar for perl (5.8.7) and try to compile it on the Solaris 8 (SPARC) box that I administrate. I try all sorts of different switches, but I can't get it to compile. I need it to be compiled with threads. Anyone have any wisdom on how best to do this? Here's a transcript of my latest attempt. It's long; you might want to skip to the bottom, where I try "make" and the fatal errors start happening.
1
7188
KevinADC
by: KevinADC | last post by:
Introduction In part one we discussed the default sort function. In part two we will discuss more advanced techniques you can use to sort data. Some of the techniques might introduce unfamiliar methods or syntax to a less experienced perl coder. I will post links to online resources you can read if necessary. Experienced perl coders might find nothing new or useful contained in this article. Short Review In part one I showed you some...
1
2287
by: pitjpz | last post by:
We have moved our Database to another server. The server it was on used SQL 4 and the new one its on now uses SQL5 the only problem we can find is that when you attempt to delete a record from the DB the following happens: When Deleting a record: Fatal Error: Can't call method "fetchrow_arrayref" on an undefined value at GT::SQL::File::delete_records line 275. Stack Trace: GT::Base (2704): main::fatal called at...
1
47462
KevinADC
by: KevinADC | last post by:
Note: You may skip to the end of the article if all you want is the perl code. Introduction Many websites have a form or a link you can use to download a file. You click a form button or click on a link and after a moment or two a file download dialog box pops-up in your web browser and prompts you for some instructions, such as “open” or “save“. I’m going to show you how to do that using a perl script. What You Need Any recent...
0
8617
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9174
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9035
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8884
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7751
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5875
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4376
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3057
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2347
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.