Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP RegExp for url string

Tags:

regex

php

Example strings:

accuracy-is-5

accuracy-is-5-or-15

accuracy-is-5-or-15-or-20

package-is-dip-8-or-dip-4-or-dip-16

My current regexp:

/^([a-z0-9\-]+)\-is\-([a-z0-9\.\-]*[a-z0-9])(?:\-or\-([a-z0-9\.\-]*[a-z0-9]))*$/U

No fixed length, part:

\-or\-[a-z0-9\.\-]

can be repeated.

Bot now from string "accuracy-is-5-or-15-or-20" i get:

Array ( [0] => accuracy-is-5-or-15-or-20 [1] => accuracy [2] => 5 [3] => 20 )

Where is 15? :) Tnx.

like image 806
NMFES Avatar asked May 27 '15 12:05

NMFES


People also ask

How check string is URL or not in PHP?

If we have text, whatever it is, I'd like to check if it is a URL or not. $text = "something.com"; //this is a url if (! IsUrl($text)){ echo "No it is not url"; exit; // die well }else{ echo "Yes it is url"; // my else codes goes } function IsUrl($url){ // ??? }

How do I validate URL?

You can use the URLConstructor to check if a string is a valid URL. URLConstructor ( new URL(url) ) returns a newly created URL object defined by the URL parameters. A JavaScript TypeError exception is thrown if the given URL is not valid.


2 Answers

^\w+(?:-[a-zA-Z]+)+\K|\G(?!^)-(\d+)(?:(?:-[a-zA-Z]+)+|$)

You can use \G here to capture all groups.Whenever a capture group is repeated the last value overwrites the previous.See demo.

https://regex101.com/r/tS1hW2/3

\G assert position at the end of the previous match or the start of the string for the first match

EDIT:

^\w+-is(?:-dip)?\K|\G(?!^)-(\d+)(?:-or(?:-dip)?|$)

You can use this if you are sure of is,or and dip.See demo.

https://regex101.com/r/tS1hW2/4

$re = "/^\\w+-is(?:-dip)?\\K|\\G(?!^)-(\\d+)(?:-or(?:-dip)?|$)/m"; 
$str = "accuracy-is-5\naccuracy-is-5-or-15\naccuracy-is-5-or-15-or-20\npackage-is-dip-8-or-dip-4-or-dip-16"; 

preg_match_all($re, $str, $matches);
like image 145
vks Avatar answered Oct 07 '22 13:10

vks


When a capture group is repeated in a pattern the previous values are overwritten with the last. So it is not possible to design your pattern like this with preg_match.

A possible workaround consists to use preg_match_all that searches all occurrences of a pattern and the \G anchor that is the position after the previous match. The pattern must be written to find one value at a time.

The \G ensures that all matches are contiguous. To be sure that the end of the string has been reached (in other word that the string is correctly formatted from start to the end), a convenient way is to create an empty capture group at the end. So if this capture group appears in the last match, that means that the format is correct.

define('PARSE_SENTENCE_PATTERN', '~
(?:                                       # two possible beginings:
    \G(?!\A)                              # - immediatly after a previous match 
  |                                       # OR
    \A                                    # - at the start of the string
    (?<subject> \w+ (?>[-.]\w+)*? ) -is-  #  (in this case the subject is captured)
)
(?<value> \w+ (?>[-.]\w+)*? )  # capture the value
(?: -or- | \z (?<check>) )     # must be followed by "-or-" OR the end of the string \z
                               # (then the empty capture group "check" is created)
~x');

function parseSentence ($sentence) {

    if (preg_match_all(PARSE_SENTENCE_PATTERN, $sentence, $matches, PREG_SET_ORDER) &&
        isset(end($matches)['check']) ) 
        return [ 'subject' => $matches[0]['subject'],
                 'values'  => array_reduce ($matches, function($c, $v) {
                                  $c[] = $v['value']; return $c; }, $c = []) ];

    return false; // wrong format

}

// tests
$test_strings = ['accuracy-is-5', 'accuracy-is-5-or-15', 'accuracy-is-5-or-15-or-20',
                 'package-is-dip-8-or-dip-4-or-dip-16',
                 'bad-format', 'bad-format-is-', 'bad-format-is-5-or-'];

foreach ($test_strings as $test_string) {
    var_dump(parseSentence($test_string));
}
like image 3
Casimir et Hippolyte Avatar answered Oct 07 '22 13:10

Casimir et Hippolyte