1

I guess this is a quite simple question but after 20 minutes of googling I couldn't find anything to solve my problem.

So I want to check a string variable whether it has 'OK' somewhere in it or not.

I tried using ~ and ~~. ~ is giving me an error and ~~ is says not the right operator is guess. I thought of ~ as something like "roughly" but it seems like that's not true. Here is my code:

open (INPUT, "<", $curfile);
while (<INPUT>) {
$firsttenchars= substr ($_, 0, 10);
if ($firsttenchars ~ "OK") 
    {
    print "success";
    }               
}
close INPUT;
Sant
  • 53
  • 7
Zesa Rex
  • 412
  • 1
  • 4
  • 16
  • 2
    When I read the title, I thought you want a fuzzy match, i.e. `ofobra` instead of `foobar`. Maybe that's why you had trouble finding what you wanted, especially if English is not your native language. Sometimes it's hard to accurately describe a problem. – simbabque Sep 20 '16 at 09:10
  • yeah, that is so true, it even took me some minutes to write this title, even though it was not really what I wouldve asked someone in my native language. – Zesa Rex Sep 20 '16 at 09:19

1 Answers1

7

You are looking for a pattern match.

if ($firsttenchars =~ m/OK/) { ... }

This will return true if the literal string 'OK' (case-sensitive) is found somewhere inside of $firsttenchars. It doesn't care how often, and once it finds it, it stops looking.

The stuff inside the // is a regular expression, short regex. Those are used to creae patterns. =~ is the binding operator that binds a scalar value ($firsttenchars) to a pattern match. The m of the m// is the match operator. There is also an s/// that is used to replace something by a pattern.

You can read perlrequick, perlre and perlretut for more information. The regex tag wiki here on Stack Overflow is an awesome resource to get started with regular expressions.


The ~ operator is the bitwise negation operator.

Unary "~" performs bitwise negation, that is, 1's complement. For example, 0666 & ~027 is 0640. (See also Integer Arithmetic and Bitwise String Operators.) Note that the width of the result is platform-dependent: ~0 is 32 bits wide on a 32-bit platform, but 64 bits wide on a 64-bit platform, so if you are expecting a certain bit width, remember to use the "&" operator to mask off the excess bits.

The ~~ operator is called smart match. It's been there for a while in Perl and it supposed to do smart things. It behaves differently based on what you've got on the RHS (right-hand side) and LHS (left-hand side). It's still considered experimental and many people in the Perl community find it controversial. You used it with two scalars, both of them containing strings. That turns it into an eq, which checks for string equality.

Any Any string equality
like: Any eq Any

A complete overview of all operators in Perl can be found in perlop. Note this links to the most recent version (5.24 at the time of writing). Your Perl might be older, and might not have all of them.


A faster way of checking if 'OK' is contained inside of that string is the index built-in. It returns the first occurrence of a string within another string. Because it returns -1 if it doesn't find that string, you need to explicitly check the return value.

if (index($firsttenchars, 'OK') != - 1) { ... }

This is a bit more to write than the pattern match, but it's a lot faster.

Community
  • 1
  • 1
simbabque
  • 53,749
  • 8
  • 73
  • 136
  • 1
    works, thanks. I really dont know if I should like the fact it is that simple or hate it because I couldn't figure it out. – Zesa Rex Sep 20 '16 at 09:07
  • 1
    @ZesaRex regex is a complicated topic, but it's very powerful, and very simple to do in Perl. If you're fairly new to Perl, I suggest you get yourself a copy of the _Learning Perl_ book, which has two chapters on regex and will take about three to five evenings to complete. Ovid's _Beginning Perl_ is also a great resource if you already know some programming. Don't beat yourself up for not knowing about this. If you've never heard that something like this exists it's not your fault you don't know. :) – simbabque Sep 20 '16 at 09:08
  • 5
    @ZesaRex You can't "_figure out_" things like this. Need to read up on it :) – zdim Sep 20 '16 at 09:08
  • `regex` in particular is a very long legacy thing - it's a lot of dark magic from back in the day when it was a command you typed in a text editor. – Sobrique Sep 20 '16 at 09:11
  • 2
    All this, and no mention of `index`? – Sinan Ünür Sep 20 '16 at 11:19
  • I can't benchmark it right now but `index` is probably not faster than a regex. I don't know all the details, but when you try to match a constant string ("OK" in that case), the regex engine is pretty efficient, and in that case, it should be the same speed as `index`. Let me know if your benchmarks show otherwise. (I'll try it when I have time anyway) – Dada Sep 20 '16 at 12:08
  • @Dada someone did here: http://stackoverflow.com/a/30752068/1331451. In that case, `index` won with flying colors. But of course it depends on the system and mostly on the Perl version. I believe there is a change coming up in 5.26 that makes static matching way faster than it was before, but I cannot find a reference for that right now. – simbabque Sep 20 '16 at 14:09
  • I don't understand your check for `index`'s return value. You are looking for `OK` anywhere in the string, not just the beginning. @Dada I made no claim that `index` is faster. However, it is the **literal** answer to the OP's question of figuring out if one constant string exists in another. – Sinan Ünür Sep 20 '16 at 17:04
  • Because it was wrong @sinan. It has to be not - 1 obviously. – simbabque Sep 20 '16 at 17:08
  • Indeed, index is faster (from 15% to a few hundreds based on what I tested), I either failed my benchs last time or got unlucky I guess. Thanks for your reply. @SinanÜnür My comment was adressed to Simbabque, I agree that this `index` can be mentioned as a legit solution, but I thought it wasn't really faster than regex. – Dada Sep 20 '16 at 18:20