Sorry to bother, I feel permanently lost when it comes to regex...
I have to match a string which occurs in a longer sequence of hex-values. My test-string is this:
BF1301020302000017BF1301030101010300FF6ABF130201010300FFC0BF1303010303030100FF98
Pattern is this:
starts with BF13
followed by an unknown amount of "01", "02" or "03" repetitions (\w\w)
00 marks the termination of the sequence between BF13 and 00
after the 00-terminator, there are always 4 additional chars
I tried BF13(\w\w)+?00(\w\w){1} but it's obviously wrong.
The test-string is supposed to match and output these values:
BF1301020302000017
BF1301030101010300FF6A
BF130201010300FFC0
BF1303010303030100FF98
Thanks, guys!
This one will do the job :
BF13(?:0[123])+00[A-Z0-9]{4}
Explanation
BF13 BF13 literally
(?:...)+ Followed by something (non capturing group) at least one time (+)
0[123] a zero followed by 1, 2 or 3
00 Followed by 00
[A-Z0-9]{4} Followed by uppercase char or a digit 4 times
RegExp Demo
Sample PHP code Test online
$re = '/BF13(?:0[123])+00[A-Z0-9]{4}/';
$str = 'BF1301020302000017BF1301030101010300FF6ABF130201010300FFC0BF1303010303030100FF98';
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
foreach ($matches as $val) {
echo "matched: " . $val[0] . "\n";
}
You have a couple of options:
Input:
$in = 'BF1301020302000017BF1301030101010300FF6ABF130201010300FFC0BF1303010303030100FF98';
Method #1 - preg_match_all() (Regex Pattern Explanation/Demo):
var_export(preg_match_all('/BF13(?:0[123])+0{2}[A-F0-9]{4}/', $in, $out) ? $out[0] : []);
// *my pattern is a couple of steps faster than stej4n's
// and doesn't make the mistake of putting commas in the character class
Method #2: - preg_split() (Regex Pattern Explanation/Demo):
var_export(preg_split('/0{2}[A-F0-9]{4}\K/', $in, 0, PREG_SPLIT_NO_EMPTY));
// K moves the match starting point -- preserving all characters when splitting
// I prefer this method because it requires a small pattern and
// it returns an array, as opposed to true/false with a variable declaration
// Another pattern for preg_split() is just slightly slower, but needs less parameters:
// preg_split('/0{2}[A-F0-9]{4}\K(?!$)/', $in)
Output (either way):
array (
0 => 'BF1301020302000017',
1 => 'BF1301030101010300FF6A',
2 => 'BF130201010300FFC0',
3 => 'BF1303010303030100FF98',
)
Related
How would I go about splitting the word:
oneTwoThreeFour
into an array so that I can get:
one Two Three Four
with preg_match ?
I tired this but it just gives the whole word
$words = preg_match("/[a-zA-Z]*(?:[a-z][a-zA-Z]*[A-Z]|[A-Z][a-zA-Z]*[a-z])[a-zA-Z]*\b/", $string, $matches)`;
You can use preg_split as:
$arr = preg_split('/(?=[A-Z])/',$str);
See it
I'm basically splitting the input string just before the uppercase letter. The regex used (?=[A-Z]) matches the point just before a uppercase letter.
You can also use preg_match_all as:
preg_match_all('/((?:^|[A-Z])[a-z]+)/',$str,$matches);
Explanation:
( - Start of capturing parenthesis.
(?: - Start of non-capturing parenthesis.
^ - Start anchor.
| - Alternation.
[A-Z] - Any one capital letter.
) - End of non-capturing parenthesis.
[a-z]+ - one ore more lowercase letter.
) - End of capturing parenthesis.
I know that this is an old question with an accepted answer, but IMHO there is a better solution:
<?php // test.php Rev:20140412_0800
$ccWord = 'NewNASAModule';
$re = '/(?#! splitCamelCase Rev:20140412)
# Split camelCase "words". Two global alternatives. Either g1of2:
(?<=[a-z]) # Position is after a lowercase,
(?=[A-Z]) # and before an uppercase letter.
| (?<=[A-Z]) # Or g2of2; Position is after uppercase,
(?=[A-Z][a-z]) # and before upper-then-lower case.
/x';
$a = preg_split($re, $ccWord);
$count = count($a);
for ($i = 0; $i < $count; ++$i) {
printf("Word %d of %d = \"%s\"\n",
$i + 1, $count, $a[$i]);
}
?>
Note that this regex, (like codaddict's '/(?=[A-Z])/' solution - which works like a charm for well formed camelCase words), matches only a position within the string and consumes no text at all. This solution has the additional benefit that it also works correctly for not-so-well-formed pseudo-camelcase words such as: StartsWithCap and: hasConsecutiveCAPS.
Input:
oneTwoThreeFour
StartsWithCap
hasConsecutiveCAPS
NewNASAModule
Output:
Word 1 of 4 = "one"
Word 2 of 4 = "Two"
Word 3 of 4 = "Three"
Word 4 of 4 = "Four"
Word 1 of 3 = "Starts"
Word 2 of 3 = "With"
Word 3 of 3 = "Cap"
Word 1 of 3 = "has"
Word 2 of 3 = "Consecutive"
Word 3 of 3 = "CAPS"
Word 1 of 3 = "New"
Word 2 of 3 = "NASA"
Word 3 of 3 = "Module"
Edited: 2014-04-12: Modified regex, script and test data to correctly split: "NewNASAModule" case (in response to rr's comment).
While ridgerunner's answer works great, it seems not to work with all-caps substrings that appear in the middle of sentence. I use following and it seems to deal with these just alright:
function splitCamelCase($input)
{
return preg_split(
'/(^[^A-Z]+|[A-Z][^A-Z]+)/',
$input,
-1, /* no limit for replacement count */
PREG_SPLIT_NO_EMPTY /*don't return empty elements*/
| PREG_SPLIT_DELIM_CAPTURE /*don't strip anything from output array*/
);
}
Some test cases:
assert(splitCamelCase('lowHigh') == ['low', 'High']);
assert(splitCamelCase('WarriorPrincess') == ['Warrior', 'Princess']);
assert(splitCamelCase('SupportSEELE') == ['Support', 'SEELE']);
assert(splitCamelCase('LaunchFLEIAModule') == ['Launch', 'FLEIA', 'Module']);
assert(splitCamelCase('anotherNASATrip') == ['another', 'NASA', 'Trip']);
A functionized version of #ridgerunner's answer.
/**
* Converts camelCase string to have spaces between each.
* #param $camelCaseString
* #return string
*/
function fromCamelCase($camelCaseString) {
$re = '/(?<=[a-z])(?=[A-Z])/x';
$a = preg_split($re, $camelCaseString);
return join($a, " " );
}
$string = preg_replace( '/([a-z0-9])([A-Z])/', "$1 $2", $string );
The trick is a repeatable pattern $1 $2$1 $2 or lower UPPERlower UPPERlower etc....
for example
helloWorld = $1 matches "hello", $2 matches "W" and $1 matches "orld" again so in short you get $1 $2$1 or "hello World", matches HelloWorld as $2$1 $2$1 or again "Hello World". Then you can lower case them uppercase the first word or explode them on the space, or use a _ or some other character to keep them separate.
Short and simple.
When determining the best pattern for your project, you will need to consider the following pattern factors:
Accuracy (Robustness) -- whether the pattern is correct in all cases and is reasonably future-proof
Efficiency -- the pattern should be direct, deliberate, and avoid unnecessary labor
Brevity -- the pattern should use appropriate techniques to avoid unnecessary character length
Readability -- the pattern should be keep as simple as possible
The above factors also happen to be in the hierarchical order that strive to obey. In other words, it doesn't make much sense to me to prioritize 2, 3, or 4 when 1 doesn't quite satisfy the requirements. Readability is at the bottom of the list for me because in most cases I can follow the syntax.
Capture Groups and Lookarounds often impact pattern efficiency. The truth is, unless you are executing this regex on thousands of input strings, there is no need to toil over efficiency. It is perhaps more important to focus on pattern readability which can be associated with pattern brevity.
Some patterns below will require some additional handling/flagging by their preg_ function, but here are some pattern comparisons based on the OP's sample input:
preg_split() patterns:
/^[^A-Z]+\K|[A-Z][^A-Z]+\K/ (21 steps)
/(^[^A-Z]+|[A-Z][^A-Z]+)/ (26 steps)
/[^A-Z]+\K(?=[A-Z])/ (43 steps)
/(?=[A-Z])/ (50 steps)
/(?=[A-Z]+)/ (50 steps)
/([a-z]{1})[A-Z]{1}/ (53 steps)
/([a-z0-9])([A-Z])/ (68 steps)
/(?<=[a-z])(?=[A-Z])/x (94 steps) ...for the record, the x is useless.
/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/ (134 steps)
preg_match_all() patterns:
/[A-Z]?[a-z]+/ (14 steps)
/((?:^|[A-Z])[a-z]+)/ (35 steps)
I'll point out that there is a subtle difference between the output of preg_match_all() and preg_split(). preg_match_all() will output a 2-dimensional array, in other words, all of the fullstring matches will be in the [0] subarray; if there is a capture group used, those substrings will be in the [1] subarray. On the other hand, preg_split() only outputs a 1-dimensional array and therefore provides a less bloated and more direct path to the desired output.
Some of the patterns are insufficient when dealing with camelCase strings that contain an ALLCAPS/acronym substring in them. If this is a fringe case that is possible within your project, it is logical to only consider patterns that handle these cases correctly. I will not be testing TitleCase input strings because that is creeping too far from the question.
New Extended Battery of Test Strings:
oneTwoThreeFour
hasConsecutiveCAPS
newNASAModule
USAIsGreatAgain
Suitable preg_split() patterns:
/[a-z]+\K|(?=[A-Z][a-z]+)/ (149 steps) *I had to use [a-z] for the demo to count properly
/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/ (547 steps)
Suitable preg_match_all() pattern:
/[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|$)/ (75 steps)
Finally, my recommendations based on my pattern principles / factor hierarchy. Also, I recommend preg_split() over preg_match_all() (despite the patterns having less steps) as a matter of directness to the desired output structure. (of course, choose whatever you like)
Code: (Demo)
$noAcronyms = 'oneTwoThreeFour';
var_export(preg_split('~^[^A-Z]+\K|[A-Z][^A-Z]+\K~', $noAcronyms, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_match_all('~[A-Z]?[^A-Z]+~', $noAcronyms, $out) ? $out[0] : []);
Code: (Demo)
$withAcronyms = 'newNASAModule';
var_export(preg_split('~[^A-Z]+\K|(?=[A-Z][^A-Z]+)~', $withAcronyms, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_match_all('~[A-Z]?[^A-Z]+|[A-Z]+(?=[A-Z][^A-Z]|$)~', $withAcronyms, $out) ? $out[0] : []);
I took cool guy Ridgerunner's code (above) and made it into a function:
echo deliciousCamelcase('NewNASAModule');
function deliciousCamelcase($str)
{
$formattedStr = '';
$re = '/
(?<=[a-z])
(?=[A-Z])
| (?<=[A-Z])
(?=[A-Z][a-z])
/x';
$a = preg_split($re, $str);
$formattedStr = implode(' ', $a);
return $formattedStr;
}
This will return: New NASA Module
Another option is matching /[A-Z]?[a-z]+/ - if you know your input is on the right format, it should work nicely.
[A-Z]? would match an uppercase letter (or nothing). [a-z]+ would then match all following lowercase letters, until the next match.
Working example: https://regex101.com/r/kNZfEI/1
You can split on a "glide" from lowercase to uppercase thus:
$parts = preg_split('/([a-z]{1})[A-Z]{1}/', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
//PREG_SPLIT_DELIM_CAPTURE to also return bracketed things
var_dump($parts);
Annoyingly you will then have to rebuild the words from each corresponding pair of items in $parts
Hope this helps
First of all codaddict thank you for your pattern, it helped a lot!
I needed a solution that works in case a preposition 'a' exists:
e.g. thisIsACamelcaseSentence.
I found the solution in doing a two step preg_match and made a function with some options:
/*
* input: 'thisIsACamelCaseSentence' output: 'This Is A Camel Case Sentence'
* options $case: 'allUppercase'[default] >> 'This Is A Camel Case Sentence'
* 'allLowerCase' >> 'this is a camel case sentence'
* 'firstUpperCase' >> 'This is a camel case sentence'
* #return: string
*/
function camelCaseToWords($string, $case = null){
isset($case) ? $case = $case : $case = 'allUpperCase';
// Find first occurances of two capitals
preg_match_all('/((?:^|[A-Z])[A-Z]{1})/',$string, $twoCapitals);
// Split them with the 'zzzzzz' string. e.g. 'AZ' turns into 'AzzzzzzZ'
foreach($twoCapitals[0] as $match){
$firstCapital = $match[0];
$lastCapital = $match[1];
$temp = $firstCapital.'zzzzzz'.$lastCapital;
$string = str_replace($match, $temp, $string);
}
// Now split words
preg_match_all('/((?:^|[A-Z])[a-z]+)/', $string, $words);
$output = "";
$i = 0;
foreach($words[0] as $word){
switch($case){
case 'allUpperCase':
$word = ucfirst($word);
break;
case 'allLowerCase':
$word = strtolower($word);
break;
case 'firstUpperCase':
($i == 0) ? $word = ucfirst($word) : $word = strtolower($word);
break;
}
// remove te 'zzzzzz' from a word if it has
$word = str_replace('zzzzzz','', $word);
$output .= $word." ";
$i++;
}
return $output;
}
Feel free to use it, and in case there is an 'easier' way to do this in one step please comment!
Full function based on #codaddict answer:
function splitCamelCase($str) {
$splitCamelArray = preg_split('/(?=[A-Z])/', $str);
return ucwords(implode($splitCamelArray, ' '));
}
In order to split my string at the point which is preceded by digit and is followed by letters as:
$str = '12jan';
I have used
$arr = preg_split('/(?<=[0-9])(?=[a-z]+)/i',$str);
It works file and gives the desired output. I want to update it so that it gives the same output for strings like.
$str='12 jan';
$str='12 jan';
$str='12/jan';
$str='12//jan';
$str='12/jan';
$str='12*/jan';
$str='12*//jan';
The code should work for any strings given above so that at the end of the day I have a array like
Array
(
[0] => 12
[1] => jan
)
Any help will be appreciated.
This may be optimized if you answer my question in the comment.
Pattern: ~(?<=[0-9])[*/ ]*(?=[a-z]+)~i
Demo
The above will match zero or more *, / and/or space characters.
On your input strings, this will be just as accurate and faster:
Pattern: ~\d+\K[^a-z]*~i
or: ~\d+\K[*/ ]*~ (no case-sensitive pattern modifier is necessary)
Demo
The above will match zero or more non-alphabetical characters immediately following the leading digit(s).
And of course preg_split's cousins can also do nicely:
Here is a battery of PHP Demos.
$strings=['12jan','12 jan','12 jan','12/jan','12//jan','12/jan','12*/jan','12*//jan'];
foreach($strings as $string){
var_export(preg_split('~(?<=[0-9])[*/ ]*(?=[a-z]+)~i',$string));
echo "\n";
var_export(preg_split('~\d+\K[*/ ]*~',$string));
echo "\n";
var_export(preg_match('~(\d+)[/* ]*([a-z]+)~i',$string,$out)?array_slice($out,1):'fail');
echo "\n";
var_export(preg_match('~(\d+)[/* ]*(.+)~',$string,$out)?array_slice($out,1):'fail');
echo "\n";
var_export(preg_match_all('~\d+|[a-z]+~i',$string,$out)?$out[0]:'fail');
echo "\n---\n";
}
All methods provide the same output.
A simple preg_match regexp does it:
foreach (['12 jan', '12 jan', '12/jan', '12//jan', '12/jan',
'12*/jan', '12*//jan'] as $test)
{
unset ($matches);
if (preg_match("#^([0-9]+)[ /*]*(.*)#", $test, $matches)) {
var_export( [$matches[1], $matches[2]] );
}
else {
print "Failed for '$test'.\n";
}
}
The regexp is:
start with numbers -> group #1
have 0 or more of space, slash or stars
take all the rest -> group #2
I have updated your code with preg_match
Its gives output what exactly your needs
$str='12/jan';
preg_match('/^(\d*)[\*\s\/]*([a-z]{3})$/i', $str, $match);
print_r($match);
but the output is changed a little bit, It will be like below
array(
0 => '12/jan',
1 => '12',
2 => 'jan'
)
I have the word AK747, I use regex to detect if a string (at least 2 chars ex: AK) is followed by a number (at least to digits ex: 747).
EDIT : (sorry that I wasn't clear on this guys)
I need to do this above because :
In some case I need to split to match search against AK-747. When I search for string 'AK-747' with keyword 'AK747' it won't find a match unless I use levenshtein in database, so I prefer splitting AK747 to AK and 747.
My code:
$strNumMatch = preg_match('/^[a-zA-Z]{2,}[0-9]{2,}$/',
$value, $match);
if(isset($match[0]))
echo $match[0];
How do I split to array ['AK', '747'] for example with preg_split() or any other way?
$input = 'AK-747';
if (preg_match('/^([a-z]{2,})-?([0-9]{2,})$/i', $input, $result)) {
unset($result[0]);
}
print_r($result);
The output:
Array
(
[1] => AK
[2] => 747
)
You may try this:
preg_match('/[0-9]{2,}/', $value, $matches, PREG_OFFSET_CAPTURE);
$position = $matches[0][1];
$letters = substr($value, 0, $position);
$numbers = substr($value, $position);
This way you get the position of the first number and split there.
EDIT:
Starting from your original approach this could look somewhat like this:
$strNumMatch = preg_match('/^([a-zA-Z]{2,})([0-9]{2,})$/', $value, $match, PREG_OFFSET_CAPTURE);
if($strNumMatch){
$position = $matches[2][1];
$letters = substr($value, 0, $position);
$numbers = substr($value, $position);
$alternative = $letters.'-'.$numbers;
}
preg_split() is a very sensible and direct call since you desire an indexed array containing the two substrings.
Code: (Demo)
$input = 'AK-747';
var_export(preg_split('/[a-z]{2,}\K-?/i',$input));
Output:
array (
0 => 'AK',
1 => '747',
)
The \K means "restart the fullstring match". Effectively, everything to the left of \K is retained as the first element in the result array and everything to right (the optional hyphen) is omitted because it is considered the delimiter. Pattern Demo
Code: (Demo)
I process a small battery of inputs to show what can be done and explain after the snippet.
$inputs=['AK747','AK-747','AK-','AK']; // variations as I understand them
foreach($inputs as $input){
echo "$input returns: ";
var_export(preg_split('/[a-z]{2,}\K-?/i',$input,2,PREG_SPLIT_NO_EMPTY));
echo "\n";
}
Output:
AK747 returns: array (
0 => 'AK',
1 => '747',
)
AK-747 returns: array (
0 => 'AK',
1 => '747',
)
AK- returns: array (
0 => 'AK',
)
AK returns: array (
0 => 'AK',
)
preg_split() takes a pattern that receives a pattern that will match a variable substring and use it as a delimiter. If - were present in every input string then explode('-',$input) would be most appropriate. However, - is optional in this task, so the pattern must allow - to be optional (this is what the ? quantifier does in all of the patterns on this page).
Now, you couldn't just use a pattern like /-?/, that would split the string on every character. To overcome this, you need to tell the regex engine the exact expected location for the optional -. You do this by referencing [a-z]{2,} before the -? (single intended delimiter).
The pattern /[a-z]{2,}-?/i does a fair job of finding the correct location for the optional hyphen, but now the trouble is, the leading letters in the string are included as part of the delimiting substring.
Sometimes, "lookarounds" can be used in regex patterns to match but not consume substrings. A "positive lookbehind" is used to match a preceding substring, however "variable length lookbehinds" are not permitted in php (and most other regex flavors). This is what the invalid pattern would look like: /(?<=[a-z]{2,})-?/i.
The way around this technicality is to "restart the fullstring match" using the \K token (aka a lookbehind alternative) just before the optional hyphen. To correctly target only the intended delimiter, the leading letters must be "matched/consumed" then "discarded" -- that's what \K does.
As for the inclusion of the 3rd and 4th parameter of preg_split()...
I've set the 3rd parameter to 2. This is just like the limit parameter that explode() has. It instructs the function to not make more than 2 output elements. For this case, I could have used NULL or -1 to mean "unlimited", but I could NOT leave the parameter empty -- it must be assigned to allow for the declaration of the 4th parameter.
I've set the 4th parameter to PREG_SPLIT_NO_EMPTY which instructs the function to not generate empty output elements.
Ta-Da!
p.s. a preg_match_all() solution is as easy as using a pipe and two anchors:
$inputs=['AK747','AK-747','AK-','AK']; // variations as I understand them
foreach($inputs as $input){
echo "$input returns: ";
var_export(preg_match_all('/^[a-z]{2,}|\d{2,}$/i',$input,$out)?$out[0]:[]);
echo "\n";
}
// same outputs as above
You can make the - optional with ?.
/([A-Za-z]{2,}-?[0-9]{2,})/
https://regex101.com/r/tIgM4F/1
I'm trying to get the string that match with original and with number in the end.
I got these strings:
mod_courts2
mod_courts_config
mod_courts_config2
From these strings I want the one that matches only with "mod_courts" with number in the end.
I'm doing this:
if (strpos($t, "mod_courts") !== FALSE) {
preg_match('/^\w+(\d+)$/U', $t, $match);
echo $match;
}
This returns me "mod_courts2" and "mod_courts_config2", I just want "mod_courts2"
Use the following regex:
/^[a-z]+_[a-z]+(\d+)$/
Explanation:
^ - assert position at the beginning of the string
[a-z]+ - match any alphabet one or more times
_ - match a literal undescore character
[a-z]+ - match any alphabet one or more times
(\d+) - match (and capture) any digit from 0 to 9 one or more times
$ - assert position at the end of the string
Test cases:
$array = array(
'mod_courts2',
'mod_courts_config',
'mod_courts_config2'
);
foreach ($array as $string) {
if(preg_match('/^[a-z]+_[a-z]+(\d+)$/i', $string, $matches)) {
print_r($matches);
}
}
Output:
Array
(
[0] => mod_courts2
[1] => 2
)
Very simply, you can do:
/^(mod_courts\d+)$/
However, if you want exactly the following format: sometext_somettext2, you can use the following regex:
/^([a-zA-Z]+_[a-zA-Z]+\d+)$/
or
/^([^_]+_[^_]+\d+)$/
Demos
http://regex101.com/r/jP8iC1
http://regex101.com/r/tI1uX8
http://regex101.com/r/fX8pO5
^mod_courts\d+$
this should do it
You can just use
^mod_courts[0-9]+$
Meaning mod_courts followed by a number (and only that, thanks to ^$ matching the beginning and end of the string). No need for the strpos check.
I have a text in PHP stored in the variable $row. I'd like to find the position of a certain group of words and that's quite easy. What's not so easy is to make my code recognize that the word it has found is exactly the word i'm looking for or a part of a larger word. Is there a way to do it?
Example of what I'd like to obtain
CODE:
$row= "some ugly text of some kind i'd like to find in someway"
$token= "some";
$pos= -1;
$counter= substr_count($row, $token);
for ($h=0; $h<$counter; $h++) {
$pos= strpos($row, $token, $pos+1);
echo $pos.' ';
}
OUTPUT:
what I obtain:
0 17 47
what I'd like to obtain
0 17
Any hint?
Use preg_match_all() with word boundaries (\b):
$search = preg_quote($token, '/');
preg_match_all("/\b$search\b/", $row, $m, PREG_OFFSET_CAPTURE);
Here, the preg_quote() statement is used to correctly escape the user input so as to use it in our regular expression. Some characters have special meaning in regular expression language — without proper escaping, those characters will lose their "special meaning" and your regex might not work as intended.
In the preg_match_all() statement, we are supplying the following regex:
/\b$search\b/
Explanation:
/ - starting delimiter
\b - word boundary. A word boundary, in most regex dialects, is a position between a word character (\w) and a non-word character (\W).
$search - escaped search term
\b - word boundary
/ - ending delimiter
In simple English, it means: find all the occurrences of the given word some.
Note that we're also using PREG_OFFSET_CAPTURE flag here. If this flag is passed, for every occurring match the appendant string offset will also be returned. See the documentation for more information.
To obtain the results you want, you can simply loop through the $m array and extract the offsets:
$result = implode(' ', array_map(function($arr) {
return $arr[1];
}, $m[0]));
echo $result;
Output:
0 18
Demo
What you're looking for is a combination of Regex with a word boundaries pattern and the flag to return the offset (PREG_OFFSET_CAPTURE).
PREG_OFFSET_CAPTURE
If this flag is passed, for every occurring match the appendant
string offset will also be returned. Note that this changes the
value of matches into an array where every element is an array
consisting of the matched string at offset 0 and its string offset
into subject at offset 1.
$row= "some ugly text of some kind i'd like to find in someway";
$pattern= "/\bsome\b/i";
preg_match_all($pattern, $row, $matches, PREG_OFFSET_CAPTURE);
And we get something like this:
Array
(
[0] => Array
(
[0] => Array
(
[0] => some
[1] => 0
)
[1] => Array
(
[0] => some
[1] => 18
)
)
)
And just loop through the matches and extract the offset where the needle was found in the haystack.
// store the positions of the match
$offsets = array();
foreach($matches[0] as $match) {
$offsets[] = $match[1];
}
// display the offsets
echo implode(' ', $offsets);
Use preg_match():
if(preg_match("/some/", $row))
// [..]
The first argument is a regex, which can match virtually anything you want to match. But, there are dire warnings about using it to match things like HTML.