Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hey All,

Been trying to learn PERL for the last 4 months. This question may be a beginner's question so sorry.

I have a variable stored inside a scalar and wish to remove a certain pattern from it if it was to be found.

Ex:
$scalar = "::fruits||apple::fruits||orange::vegetable||celery::vegetab +le||lettuce";
Now this scalar stores a list, a fruit or vegetable and the name of the item.

The patter goes as: ::fruit||item::vegetable||item so the "::" pattern sepearates each item, and the "||" pattern seperates the category (fruit or vegetable) and item name.

Now if I wanted to delete "Celery" off the list, I would need to look for the pattern ""::vegetable||celery" and remove it from the scalar. How can I do this? I checked in my Perl Cookbook I purchased but coulnd't find anything suited for this in the pattern matching area.

Any suggestions would be greatly appreciated.

Thanks,

Henry

Replies are listed 'Best First'.
Re: Removing a Pattern matched in a Scalar
by Zaxo (Archbishop) on Jul 25, 2005 at 06:06 UTC

    You can split up the records and grep out the celery: $scalar = join '::', grep { ! /celery/ } split /::/, $scalar;

    After Compline,
    Zaxo

Re: Removing a Pattern matched in a Scalar
by jbrugger (Parson) on Jul 25, 2005 at 06:09 UTC
    Well, i'd choose to put these things in arrays and hashes if i where you, this is a string, where you use :: and || as delimiters.
    In this case, it's easy to remove using a regexp, since you allways start with ::
    #!/usr/bin/perl # use strict; my $scalar = "::fruits||apple::fruits||orange::vegetable||celery::vege +table||lettuce"; $scalar =~ s/::vegetable\|\|celery//; print $scalar;
    Anyway, play with it, and try something like this:
    #!/usr/bin/perl # use strict; use Data::Dumper; my @arr = ( {fruits => "apple"}, {fruits => "orange"}, {vegetable => "celery"}, ); print Dumper(@arr);
    "We all agree on the necessity of compromise. We just can't agree on when it's necessary to compromise." - Larry Wall.
      It looked more natural to me to express the keys and values in reverse, than have to force an array into it:
      my %hash = ( apple => fruits, orange => fruits, celery => vegetable );

      One world, one people

Re: Removing a Pattern matched in a Scalar
by prasadbabu (Prior) on Jul 25, 2005 at 06:10 UTC

    If i understood you question correctly, do you want something like this.

    $name = 'celery'; $scalar = "::fruits||apple::fruits||orange::vegetable||celery::vegetab +le||lettuce"; $scalar =~ s/::(fruits|vegetable)\|\|$name//gsi; print "$scalar";

    Thanks in advance

    Prasad

      Hey,

      seems like most of your replies all worked wonderfully :)

      Thanks a lot, and jbrugger I will take your advice and read more about Data::Dumper and formating this list inside hashes.

      Herny
Re: Removing a Pattern matched in a Scalar
by siliconGopher (Initiate) on Jul 25, 2005 at 10:03 UTC
    hey, I assume that you were not able to match the pattern simply because you did not escape the 'special characters', namely the ":"s and the "|"s. If you can escape all the special chars, you'll probably be able to solve this yourself. Sample code that should work for multiple lines like the one you defined into $scalar, only that the "scalar list" would be put into a file which in my case is defined as scalar.txt.
    ============================================================ use strict; use FileHandle; my $scalar_file = shift @ARGV; chomp($scalar_file); my $scalar_handle = new FileHandle ("$scalar_file") or die "Error:Unab +le to open file $scalar_file\n"; my $scalar; while (defined($scalar = <$scalar_handle>)){ print "Scalar : $scalar\n"; $scalar =~ s"\:\:vegetable\|\|celery""g; print "Changed Sclalar:$scalar\n"; } ============================================================
    I would however also suggest that this form of formatting could be cumbersome in complex code. Suggest you switch to arrays/hashes/csv's for data like this.
    Wisdom: For every problem there is a solution that is simple, neat and wrong.

      I assume that you were not able to match the pattern simply because you did not escape the 'special characters', namely the ":"s and the "|"s.

      As far as regexes go, there's nothing special about ":"s. E.g.:

      % perl -wle '$x=q(ab::cd); $x=~s/b::c//; print $x' ad

      the lowliest monk

Re: Removing a Pattern matched in a Scalar
by TedPride (Priest) on Jul 25, 2005 at 08:13 UTC
    There might be more categories, in which case putting each one in your regex is inefficient. It's much better to just match on any word string for category. Also, lowercasing your item name should be more efficient than using the i flag, unless your list of items is very small.
    use strict; use warnings; my $scalar = "::fruits||apple::fruits||orange::vegetable||celery::vege +table||lettuce"; my $word = "Celery"; $word = lc $word; $scalar =~ s/::\w+\|\|$word//g; print $scalar;
    If of course you'll be doing many changes to the list in a single run, you'll want to convert it to nested hashes:
    use strict; use warnings; use Data::Dumper; my (%hash, $cat, $item); my $scalar = "::fruits||apple::fruits||orange::vegetable||celery::vege +table||lettuce"; my $word = 'Celery'; $scalar =~ s/^:://; for (split /::/, $scalar) { ($cat, $item) = split /\|\|/; $hash{$cat}{$item} = (); } $word = lc $word; for $cat (keys %hash) { delete $hash{$cat}{$word} if exists $hash{$cat}{$word}; } print Dumper(\%hash); $scalar = ''; for $cat (sort keys %hash) { for $item (sort keys %{$hash{$cat}}) { $scalar .= "::$cat||$item"; } } print $scalar;