Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Separating an array into .htm elements and directory elements 2

Status
Not open for further replies.

chrismassey

Programmer
Aug 24, 2007
264
GB
Hello,

I have an array which contains a number of elements, some end in .htm (html pages) and others nothing (directories). I use a foreach loop to check which contain .htm and which don't. I then separate these into separate arrays. However I am having a problem with counting whilst placing the elements into their new arrays. Here is the section of code...

Code:
$counter = 1;
foreach (@directory_contents) {


if ($_ =~ m/.htm/) {
@page_array[$counter] = $_;
} 

else {
@directory_array[$counter] = $_;
}

$counter++;
}

As you can see, the counter will add one each time the loop goes round. Therefore the two new arrays don't have their own unique counter and elements will not be placed into the array in order. For example...

@directory_contents = ('a', 'b.htm', 'c.htm', 'd', 'e.htm');

The @page_array array will = ('', 'b.htm', 'c.htm', '', 'e.htm');
But should = ('b.htm', 'c.htm', 'e.htm');

And the @directory_array array will = ('a', '', '', 'd', '');
But should = ('a', 'd');

How can I complete this task? I cannot think of a logical way.

Thank you very much,

Chris

 
Is there a way to say...

if ($_ ne~ m/.htm/) {

So if not equal .htm

?
 
Ok, I have changed the code a bit, but the result is still not expected...

Code:
$counter = 1;
foreach (@directory_contents) {
if ($_ =~ m/.htm/) {
@page_array[$counter] = $_;
}
$counter++;
}

$counter = 1;
foreach (@directory_contents) {
if ($_ !=~ m/.htm/) {
@directory_array[$counter] = $_;
}
$counter++;
}

The result is...
@directory_array: Products Contact Page2.htm Page4.htm Welcome About Page1.htm Page3.htm

@page_array: Page2.htm Page4.htm Page1.htm Page3.htm

Thanks

 
Hello again,

Sorry I keep replying but I keep trying new methods. I still get the same results as my previous reply but I am using grep instead now (cleaner code)...

Code:
@page_array = grep { $_ =~ m/.htm/ } @directory_contents;
@directory_array = grep { $_ !=~ m/.htm/ } @directory_contents;

I get impatient. Really I should wait until I have exhausted using every method possible, before posting a topic.
 
You might want to change it to /\.htm$/
and !~ is the opposite of =~

but I would just stick with do a if and else and not two seperate loops

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
travs,

Thank you very very much. I tried changing !=~ to !~ first and it worked perfectly. I am going to stick to using the grep method, and its a cleaner method.

Chris
 
Working from your last example:

First, you don't need to specify $_ in a regex. It defaults to working with $_

Second, the period ('.') has a meaning within a regex. It means 'any character except newline'. You need to escape it for it to mean 'a period'.

Third, you'll want to anchor the .htm to the end of the string, so you don't get false positives. Probably not an issue in this exact example, but best get into the habit now.

With this in mind, you can re-write your first grep as:

Code:
@page_array = grep { /.*\.htm$/ } @directory_contents;

Next, the syntax for "not match" is:

$_ !~ m/regex/ (in your syntax)

which is more conveniently written (when $_ is the subject) as:

!/regex/

Which means your second grep is:

Code:
@directory_array = grep { !/.*\.htm$/ } @directory_contents;

 
heh.. travs got in there whilst I was typing.

and as he said, an if..else would be more efficient.

Code:
foreach (@directory_contents) {
  if ( /\.htm$/ ) {
    push @page_array, $_;
  } else {
    push @directory_array, $_;
  }
}


 
brigmar,

Thank you alot for your response. You and travs have just solved another problem I have been having, but I have ignored it for the time being. If a name contained the string htm then it would be considered a .htm file, and I was confused because I didn't realise that the . meant any character in a regex so I never escaped it.

Also I had only learnt how to append to an array using i.e. @array[n] and I have now looked up push and I see now that push places the new element onto the end of the array.

I've gone back to the foreach method. And I am now changing all the /.htm/'s across my scripts to /\.htm/. Because you guys have solved an important issue for me, you definately deserve the first 2 stars I have given in the perl forum.

Thanks again
 
Also, you don't need to maintain a count, as arrays know how big they are.If you use an array in a scalar context (or force one using scalar), you will have the count automatically.

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::perlDesignPatterns)[/small]
 
yeah.. you can get rid of the counting and just use push @array, $val
but glad we can help

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
Yeah, thank you, I see now,

In my first method I was forced to use a count so that the script knew which position to place the element...

However I can see the push efficiently places the new element to the end of the array automatically.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top