help amend this regex to only include part numbers that have both letters and numbers

I have the following regex to parse a string looking for likely candidates for part numbers/serial numbers.
$regexForModelNo = "@\b((?=[A-Za-z/ -]{0,13}\d)[A-Za-z0-9/ -]{3,14})\b@";

Open in new window

It works fine but the odd time it spits out some random matches along with good matches, for example it sometimes includes parts of words that arent really any likely match to part numbers. How would I modify the above to check that all matched parts must contain at least one number in there?
LVL 11
SlimshaneeyAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Bob LearnedCommented:
It would help to know the input values, and the values that don't match correctly...
SlimshaneeyAuthor Commented:
An example would be "Stringstringstring  part rb212x stringstringstring" would return "part rb212x", but I want to ignore the "part bit as it contains no numbers.
Bob LearnedCommented:
Thank you.  I just realized that it would help to know where you are using this regular expression (PHP, .NET, Perl, ...)?
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

SlimshaneeyAuthor Commented:
Its PHP, sorry,  should have mentioned in opening post
käµfm³d 👽Commented:
Can you provide the rules for a valid serial number? You've got spaces in your regex, but I would think that a serial number wouldn't contain spaces.
Carl BohmanCommented:
Based on what you've said so far, perhaps just removing the space from the look-ahead assertion would give you the results you're looking for:
$regexForModelNo = "@\b((?=[A-Za-z/-]{0,13}\d)[A-Za-z0-9/ -]{3,14})\b@";

Open in new window

With that change, the first part of the serial number must contain a number, but can also contain leters or a dash.
Ray PaseurCommented:
You might be asking too much of a single regular expression.  A function like this may be easier to write and debug.
http://www.laprbass.com/RAY_temp_slimshaneey.php

You might also enjoy reading about test-driven development.  The article looks like it is about building regular expressions, but it is really about how to think about programming problems in a practical and structured way.
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_7830-A-Quick-Tour-of-Test-Driven-Development.html
<?php // RAY_temp_slimshaneey.php
error_reporting(E_ALL);
echo "<pre>";

// THE TEST DATA
$txt = "Stringstringstring  part rb212x stringstringstring or A212x";

// A FUNCTION TO FIND SERIAL NUMBERS
function find_sn($str)
{
    // A REGULAR EXPRESSION TO ISOLATE SUBSTRINGS
    $rgx
    = '#'             // REGEX DELIMITER
    . '\b'            // WORD BOUNDARY
    . '('             // GROUP
    . '.*?'           // OF ANYTHING
    . ')'             // END GROUP
    . '\b'            // WORD BOUNDARY
    . '#'             // END REGEX
    ;

    // A REGULAR EXPRESSION TO MATCH LETTERS
    $ltr = '#[A-Z]#i';

    // A REGULAR EXPRESSION TO MATCH NUMBERS
    $num = '#[0-9]#';

    if (!preg_match_all($rgx, $str, $mat)) return FALSE;

    $out = array();

    // LOOK FOR BOTH LETTERS AND NUMBERS IN EACH OF THE SUBSTRINGS
    foreach ($mat[0] as $txt)
    {
        if (preg_match($ltr, $txt))
        {
            if (preg_match($num, $txt))
            {
                $out[] = $txt;
            }
        }
    }

    // ANY FINDINGS?
    if (empty($out)) return FALSE;
    return $out;
}

// TEST THE FUNCTION
print_r( find_sn($txt) );

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Carl BohmanCommented:
If you can define what is being looked for, it is a lot easier to create a regex (or any function) to find it.  TheLearnedOne asked about positive and negative test cases.  kaufmed asked for the definition of what you are looking for.  Either of these would help in coming up with the proper regex (or function, if you want).

Based on what has been written so far, it sounds like a serial number is defined as a sequence of characters with the following attributes:
1. 3-14 characters in length;
2. Contains a combination of letters, numbers, dashes, slashes (/), and spaces;
3. Is not touching other words (i.e., contained between word boundaries);
4. Contains at least one number; and
5. (I assume) Contains at least one number prior to any spaces.

Adding more description to the definition (or correcting errors in it) will allow for more refining of the regex.
SlimshaneeyAuthor Commented:
Thanks guys, I looked at many options on this, it ended up being a much more simple regex query (Ive included it below, it basically finds groups of clustered characters that contains at least a number). You advice and insight set me on a very productive learning curve though. Sorry for getting back to this so late. Finally getting round to some cleanup.

[A-Za-z0-9-.]{4,}(?<=\d)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Regular Expressions

From novice to tech pro — start learning today.