php regex lookahead - exclude character - php

I’m trying to extract three parts with a regular expression.
It works for the controller and the id but not for the slug, I can not remove the last -
<?php
$url = "/cockpit/posts/my-second-article-2-155";
$routes = [];
$patterns = "/(?<controller>[a-z]+)\/(?<slug>[a-z0-9\-]+)(?<=\-)(?<id>[0-9]+)/i";
preg_match($patterns, $url, $matches);
foreach ($matches as $key => $value){
if(!is_numeric($key)){
$routes[$key] = $value;
}
}
var_dump($routes);
I get the following result :
array(3) {
["controller"]=>
string(5) "posts"
["slug"]=>
string(20) "my-second-article-2-"
["id"]=>
string(3) "155"
}
But i want this slug :
["slug"]=>
string(20) "my-second-article-2"
Thanks

You may use the following regex pattern:
/(?<controller>[a-z]+)\/(?<slug>[a-z0-9]+(?:-[a-z0-9]+)+)-(?<id>[0-9]+)/i
Your updated PHP script:
$url = "/cockpit/posts/my-second-article-2-155";
$routes = [];
$patterns = "/(?<controller>[a-z]+)\/(?<slug>[a-z0-9]+(?:-[a-z0-9]+)+)-(?<id>[0-9]+)/i";
preg_match($patterns, $url, $matches);
foreach ($matches as $key => $value) {
if (!is_numeric($key)) {
$routes[$key] = $value;
}
}
var_dump($routes);
This prints:
array(3) {
["controller"]=>
string(5) "posts"
["slug"]=>
string(19) "my-second-article-2"
["id"]=>
string(3) "155"
}
The final portion of the updated regex says to match:
[a-z0-9]+ alphanumeric term
(?:-[a-z0-9]+)+ followed by hyphen and another alphanumeric term, both 1 or more times
- match a literal hyphen
[0-9]+ match the id

Related

How to check specific string sequance using the regular expression in PHP

I am trying to create a regular expression to extract company details from a list of companies, but is facing difficulty because some companies have their mobile number listed before the company code and some have it listed after. They only want to match companies that have the mobile number listed after the company code and have tried using a look ahead in the regular expression but it hasn't been successful.
my regex syntax
details of the company:(?<address>[^\n\r]*)\b(?!.*mobile).*(company-code:)(.*?)(mobile:)(.*?)
strings to be checked:
details of the company: name:xyz, company-code:100, mobile:123
details of the company: name:xyz, mobile:12345, company-code:100
I suggest looking at it a little differently. From a more generic perspective your strings have a pattern of prefix: field1:value1, field2:value2, .... So you can focus on matching the field:value pairs. Using preg_match_all() you can fetch all matches as sets.
$data = [
'details of the company: name:xyz, company-code:100, mobile:123',
'details of the company: name:xyz, mobile:12345, company-code:100',
];
$pattern = '((?<field>[a-z-]+):\s*(?<value>[^,:]+)(?:,|$))';
$companies = [];
foreach ($data as $subject) {
if (preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)) {
// new company array
$company = [];
// iterate and add found fields
foreach ($matches as $match) {
$company[$match['field']] = $match['value'];
}
// add company array to list
$companies[] = $company;
}
}
var_dump($companies);
Output:
array(2) {
[0]=>
array(3) {
["name"]=>
string(3) "xyz"
["company-code"]=>
string(3) "100"
["mobile"]=>
string(3) "123"
}
[1]=>
array(3) {
["name"]=>
string(3) "xyz"
["mobile"]=>
string(5) "12345"
["company-code"]=>
string(3) "100"
}
}
Another solution would be to use string functions. Remove all unnecessary parts from the subject and then split it.
$prefix = 'details of the company: ';
$companies = [];
foreach ($data as $subject) {
$subject = substr($subject, strlen($prefix));
$pairs = explode(',', $subject);
$company = [];
foreach ($pairs as $pair) {
[$field, $value] = explode(':', $pair);
$company[trim($field)] = trim($value);
}
$companies[] = $company;
}
var_dump($companies);

$matches is returning same value in preg_match_all

I have array of links, i am trying to match using preg_match_all,regex but it is giving me the same result each and every time
foreach ($result[0] as $temp) {
preg_match_all($regex1, $temp["content"], $matches);
$storeUrl[]= $matches;
}
foreach ($storeUrl as $tem) {
preg_match_all($regex2, $tem[],$matches);
$storeUrllist [$count1++]= $matches;
}
$matches is working fine for first foreach and second foreach it is always returning same output only even it is not matching
I'm just guessing that you might want to design an expression that'd be similar to:
\b(?:https?:\/\/)?(?:www\.)?\w+\.(?:org|org2|com)\b
or:
\b(?:https?:\/\/)(?:www\.)?\w+\.(?:org|org2|com)\b
or:
\b(?:https?:\/\/)(?:www\.)\w+\.(?:org|org2|com)\b
not sure though.
Test
$re = '/\b(?:https?:\/\/)?(?:www\.)?\w+\.(?:org|org2|com)\b/m';
$str = 'some content http://alice.com or https://bob.org or https://www.foo.com or or baz.org2 ';
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
var_dump($matches);
Output
array(4) {
[0]=>
array(1) {
[0]=>
string(16) "http://alice.com"
}
[1]=>
array(1) {
[0]=>
string(15) "https://bob.org"
}
[2]=>
array(1) {
[0]=>
string(19) "https://www.foo.com"
}
[3]=>
array(1) {
[0]=>
string(8) "baz.org2"
}
}
The expression is explained on the top right panel of regex101.com, if you wish to explore/simplify/modify it, and in this link, you can watch how it would match against some sample inputs, if you like.

Get between brackets and word PHP

Im trying to extract a specific value from multiple strings. Lets say i have the following strings:
/a-url/{some_hash}/
/user/{user_hash}/
/user-overview/{date_hash}/{user_hash}
I want to extract all between curly bracket open and _hash}, how can i achieve this?
The output should be a array:
$array = [
'some_hash',
'user_hash',
'date_hash',
'user_hash'
];
Current code:
$matches = [];
foreach (\Route::getRoutes()->getRoutes() as $route) {
$url = $route->getUri();
preg_match_all('/({.*?_hash})/', $url, $matches);
}
You can use regex for that:
$s = '/a-url/{some_hash}/
/user/{user_hash}/
/user-overview/{date_hash}/{user_hash}';
preg_match_all('/{(.*?_hash)}/', $s, $m);
var_dump($m[1]);
The output will be:
array(4) {
[0]=>
string(9) "some_hash"
[1]=>
string(9) "user_hash"
[2]=>
string(9) "date_hash"
[3]=>
string(9) "user_hash"
}
Based on your edit you probably want:
$all_matches = [];
foreach (\Route::getRoutes()->getRoutes() as $route) {
$url = $route->getUri();
preg_match_all('/{(.*?_hash)}/', $url, $matches);
$all_matches = array_merge($all_matches, $matches[1]);
}
var_dump($all_matches);

PHP: How to get specific word from string

This is my string: $string="VARHELLO=helloVARWELCOME=123qwa";
I want to get 'hello' and '123qwa' from string.
My pseudo code is.
if /^VARHELLO/ exist
get hello(or whatever comes after VARHELLO and before VARWELCOME)
if /^VARWELCOME/ exist
get 123qwa(or whatever comes after VARWELCOME)
Note: values from 'VARHELLO' and 'VARWELCOME' are dynamic, so 'VARHELLO' could be 'H3Ll0' or VARWELCOME could be 'W3l60m3'.
Example:
$string="VARHELLO=H3Ll0VARWELCOME=W3l60m3";
Here is some code that will parse this string out for you into a more usable array.
<?php
$string="VARHELLO=helloVARWELCOME=123qwa";
$parsed = [];
$parts = explode('VAR', $string);
foreach($parts AS $part){
if(strlen($part)){
$subParts = explode('=', $part);
$parsed[$subParts[0]] = $subParts[1];
}
}
var_dump($parsed);
Output:
array(2) {
["HELLO"]=>
string(5) "hello"
["WELCOME"]=>
string(6) "123qwa"
}
Or, an alternative using parse_str (http://php.net/manual/en/function.parse-str.php)
<?php
$string="VARHELLO=helloVARWELCOME=123qwa";
$string = str_replace('VAR', '&', $string);
var_dump($string);
parse_str($string);
var_dump($HELLO);
var_dump($WELCOME);
Output:
string(27) "&HELLO=hello&WELCOME=123qwa"
string(5) "hello"
string(6) "123qwa"
Jessica's answer is perfect, but if you want to get it using preg_match
$string="VARHELLO=helloVARWELCOME=123qwa";
preg_match('/VARHELLO=(.*?)VARWELCOME=(.*)/is', $string, $m);
var_dump($m);
your results will be $m[1] and $m[2]
array(3) {
[0]=>
string(31) "VARHELLO=helloVARWELCOME=123qwa"
[1]=>
string(5) "hello"
[2]=>
string(6) "123qwa"
}

PHP Regular Expression to extract JSON data

I have the following string:
window['test'] = false;
window['options'] = true;
window['data'] = { "id" : 2345, "stuff": [{"id":704,"name":"test"};`
How would I go about extracting the JSON data in window['data']? The example data I provided is just a small sample of what really exists. There could be more data before and/or after window['data'].
I've tried this but had no luck:
preg_match( '#window["test"] = (.*?);\s*$#m', $html, $matches );
There are several issues that I can see.
Your string uses single quotes: window['test'] not window["test"], which you have in your regular expression. This means you should use double quotes to enclose your regular expression (or escape the quotes).
Your regular expression has unescaped brackets, which is used to create a character class. You should use \[ instead of just [.
You say you are looking for data but your regular expression looks for test.
You have a $ at the end of the regular expression, which means you won't match if there is nothing other than whitespace after the bit you matched.
Also your data seems incomplete, there are some missing brackets at the end, but I think that is just a copy-paste error.
So I would try:
php > preg_match("#window\['data'\]\s*=\s*(.*?);#", $html, $matches);
php > print_r($matches);
Array
(
[0] => window['data'] = {"id":2345,"stuff":[{"id":704,"name":"test"};
[1] => {"id":2345,"stuff":[{"id":704,"name":"test"}
)
Of course then you must use json_decode() to convert the JSON string ($matches[1]) into an object or associative array that you can use.
You can use this regex:
window\['data'\]\s*=\s*(.*?);
Working demo
The match information is:
MATCH 1
1. [67-111] `{"id":2345,"stuff":[{"id":704,"name":"test"}`
As regex101 suggests you could have a code like this:
$re = "/window\\['data'\\]\\s*=\\s*(.*);/";
$str = "window['test'] = false; window['options'] = true; window['data'] = {\"id\":2345,\"stuff\":[{\"id\":704,\"name\":\"test\"};";
preg_match_all($re, $str, $matches);
You can parse the window data with the regular expression:
/^window\[['"](\w+)['"]\]\s*=\s*(.+);\s*$/m
Then you can retrieve the pieces by their original index in the window data structures, and parse the JSON at your leisure.
$data = <<<_E_
window['test'] = false;
window['options'] = true;
window['data'] = { "id" : 2345, "stuff": [{"id":704,"name":"test"}]};
_E_;
$regex = <<<_E_
/^window\[['"](\w+)['"]\]\s*=\s*(.+);\s*$/m
_E_; // SO syntax highlighting doesnt like HEREDOCs "
if( preg_match_all($regex,$data,$matches) > 0 ) {
var_dump($matches);
$index = array_search('data',$matches[1]);
if( $index !== 0 ) {
var_dump(json_decode($matches[2][$index]));
} else { echo 'no data section'; }
} else { echo 'no matches'; }
Output:
// $matches
array(3) {
[0]=>
array(3) {
[0]=> string(24) "window['test'] = false; "
[1]=> string(26) "window['options'] = true; "
[2]=> string(69) "window['data'] = { "id" : 2345, "stuff": [{"id":704,"name":"test"}]};"
}
[1]=>
array(3) {
[0]=> string(4) "test"
[1]=> string(7) "options"
[2]=> string(4) "data"
}
[2]=>
array(3) {
[0]=> string(5) "false"
[1]=> string(4) "true"
[2]=> string(51) "{ "id" : 2345, "stuff": [{"id":704,"name":"test"}]}"
}
}
// decoded JSON
object(stdClass)#1 (2) {
["id"]=> int(2345)
["stuff"]=>
array(1) {
[0]=>
object(stdClass)#2 (2) {
["id"]=> int(704)
["name"]=> string(4) "test"
}
}
}
Note: I fixed the JSON in your example to be valid so it would actually parse.

Categories