Preg matching and counting the resulting match in a short string - php

I already have a function that counts the number of items in a string ($paragraph) and tells me how many characters the result is, ie tsp and tbsp present is 7, I can use this to work out the percentage of that string is.
I need to reinforce this with preg_match because 10tsp should count as 5.
$characters = strlen($paragraph);
$items = array("tsp", "tbsp", "tbs");
$count = 0;
foreach($items as $item) {
//Count the number of times the formatting is in the paragraph
$countitems = substr_count($paragraph, $item);
$countlength= (strlen($item)*$countitems);
$count = $count+$countlength;
}
$overallpercent = ((100/$characters)*$count);
I know it would be something like preg_match('#[d]+[item]#', $paragraph) right?
EDIT sorry for the curve ball but there might be a space inbetween the number and the $item, can one preg_match catch both instances?

It's not quite clear to me what you are trying to do with the regex, but if you are just trying to match for a particular number-measurement combination, this might help:
$count = preg_match_all('/\d+\s*(tbsp|tsp|tbs)/', $paragraph);
This will return the number of times a number-measurement combination occurs in $paragraph.
EDIT switched to use preg_match_all to count all occurrences.
Example for counting the number of matched characters:
$paragraph = "5tbsp and 10 tsp";
$charcnt = 0;
$matches = array();
if (preg_match_all('/\d+\s*(tbsp|tsp|tbs)/', $paragraph, $matches) > 0) {
foreach ($matches[0] as $match) { $charcnt += strlen($match); }
}
printf("total number of characters: %d\n", $charcnt);
Output from executing the above:
total number of characters: 11

Related

Find the last numeric value in a string [duplicate]

This question already has answers here:
Get last whole number in a string
(7 answers)
Closed 6 months ago.
I have this string #22aantal283xuitvoeren.
What is the best way to find the last numeric value in a string? (283 in this case)
I don't think chop() or substr() is the wat to go.
You can use preg_match_all and match all digits.
Then the last item in the array is the last number in the string.
$s = "#22aantal283xuitvoeren";
preg_match_all("/\d+/", $s, $number);
echo end($number[0]); // 283
https://3v4l.org/44VUJ
You could try preg_match_all():
$string = "#22aantal283xuitvoeren";
$result = preg_match_all(
"/(\d+)/",
$string,
$matches);
$lastNumericValueInString = array_pop($matches[1]);
echo $lastNumericValueInString;
Echoes 283
Here is a solution without regex.
Basically loop from back to front until the first number is found. Then, loop until the first non-number is found.
$string = "#22aantal283xuitvoeren";
for($i = strlen($string) - 1; $i >= 0; --$i) {
if(is_numeric($string[$i])) {
// found the first number from back to front
$number = $string[$i];
while(--$i >= 0 && is_numeric($string[$i])) {
$number = $string[$i].$number;
}
break;
}
}
// $number is now "283"
// if you want an integer, use intval($number)

Count consecutive occurence of specific, identical characters in a string - PHP

I am trying to calculate a few 'streaks', specifically the highest number of wins and losses in a row, but also most occurences of games without a win, games without a loss.
I have a string that looks like this; 'WWWDDWWWLLWLLLL'
For this I need to be able to return:
Longest consecutive run of W charector (i will then replicate for L)
Longest consecutive run without W charector (i will then replicate for L)
I have found and adapted the following which will go through my array and tell me the longest sequence, but I can't seem to adapt it to meet the criteria above.
All help and learning greatly appreciated :)
function getLongestSequence($sequence){
$sl = strlen($sequence);
$longest = 0;
for($i = 0; $i < $sl; )
{
$substr = substr($sequence, $i);
$len = strspn($substr, $substr{0});if($len > $longest)
$longest = $len;
$i += $len;
}
return $longest;
}
echo getLongestSequence($sequence);
You can use a regular expression to detect sequences of identical characters:
$string = 'WWWDDWWWLLWLLLL';
// The regex matches any character -> . in a capture group ()
// plus as much identical characters as possible following it -> \1+
$pattern = '/(.)\1+/';
preg_match_all($pattern, $string, $m);
// sort by their length
usort($m[0], function($a, $b) {
return (strlen($a) < strlen($b)) ? 1 : -1;
});
echo "Longest sequence: " . $m[0][0] . PHP_EOL;
You can achieve the maximum count of consecutive character in a particular string using the below code.
$string = "WWWDDWWWLLWLLLL";
function getLongestSequence($str,$c) {
$len = strlen($str);
$maximum=0;
$count=0;
for($i=0;$i<$len;$i++){
if(substr($str,$i,1)==$c){
$count++;
if($count>$maximum) $maximum=$count;
}else $count=0;
}
return $maximum;
}
$match="W";//change to L for lost count D for draw count
echo getLongestSequence($string,$match);

PHP replace a random word of a string

I want to replace one random word of which are several in a string.
So let's say the string is
$str = 'I like blue, blue is my favorite colour because blue is very nice and blue is pretty';
And let's say I want to replace the word blue with red but only 2 times at random positions.
So after a function is done the output could be like
I like red, blue is my favorite colour because red is very nice and blue is pretty
Another one could be
I like blue, red is my favorite colour because blue is very nice and red is pretty
So I want to replace the same word multiple times but every time on different positions.
I thought of using preg_match but that doesn't have an option that the position of the words peing replaced is random also.
Does anybody have a clue how to achieve this?
Much as I am loathed to use regex for something which is on the face of it very simple, in order to guarantee exactly n replaces I think it can help here, as it allows use to easily use array_rand(), which does exactly what you want - pick n random items from a list of indeterminate length (IMPROVED).
<?php
function replace_n_occurences ($str, $search, $replace, $n) {
// Get all occurences of $search and their offsets within the string
$count = preg_match_all('/\b'.preg_quote($search, '/').'\b/', $str, $matches, PREG_OFFSET_CAPTURE);
// Get string length information so we can account for replacement strings that are of a different length to the search string
$searchLen = strlen($search);
$diff = strlen($replace) - $searchLen;
$offset = 0;
// Loop $n random matches and replace them, if $n < 1 || $n > $count, replace all matches
$toReplace = ($n < 1 || $n > $count) ? array_keys($matches[0]) : (array) array_rand($matches[0], $n);
foreach ($toReplace as $match) {
$str = substr($str, 0, $matches[0][$match][1] + $offset).$replace.substr($str, $matches[0][$match][1] + $searchLen + $offset);
$offset += $diff;
}
return $str;
}
$str = 'I like blue, blue is my favorite colour because blue is very nice and blue is pretty';
$search = 'blue';
$replace = 'red';
$replaceCount = 2;
echo replace_n_occurences($str, $search, $replace, $replaceCount);
See it working
echo preg_replace_callback('/blue/', function($match) { return rand(0,100) > 50 ? $match[0] : 'red'; }, $str);
Well, you could use this algorithm:
calculate the random amount of times you want to replace the string
explode the string into an array
for that array replace the string occurence only if a random value between 1 and 100 is % 3 (for istance)
Decrease the number calculated at point 1.
Repeat until the number reaches 0.
<?php
$amount_to_replace = 2;
$word_to_replace = 'blue';
$new_word = 'red';
$str = 'I like blue, blue is my favorite colour because blue is very nice and blue is pretty';
$words = explode(' ', $str); //convert string to array of words
$blue_keys = array_keys($words, $word_to_replace); //get index of all $word_to_replace
if(count($blue_keys) <= $amount_to_replace) { //if there are less to replace, we don't need to randomly choose. just replace them all
$keys_to_replace = array_keys($blue_keys);
}
else {
$keys_to_replace = array();
while(count($keys_to_replace) < $amount_to_replace) { //while we have more to choose
$replacement_key = rand(0, count($blue_keys) -1);
if(in_array($replacement_key, $keys_to_replace)) continue; //we have already chosen to replace this word, don't add it again
else {
$keys_to_replace[] = $replacement_key;
}
}
}
foreach($keys_to_replace as $replacement_key) {
$words[$blue_keys[$replacement_key]] = $new_word;
}
$new_str = implode(' ', $words); //convert array of words back into string
echo $new_str."\n";
?>
N.B. I just realized this will not replace the first blue, since it is entered into the word array as "blue," and so doesn't match in the array_keys call.

Select random strings over 6 and under 10 characters from text file

I have a text file, and I need to pick a random string that is over 6 characters and under 10 characters. Normally, I would use a script like this, which would work, but since it needs to be a certain length, that won't work. Does anybody have a solution to this?
A sample input would be something like this:
Apple
Banana
Orange
Strawberry
Blueberry
Pineapple
Somelongfruithere
Those values would be in a .txt file, each with a line break. An example of a string that would be allowed is pineapple, but apple or Somelongfruithere wouldn't be allowed.
You'll need to do something like this:
$lines = array();
$tmpLines = file('random.txt');
for($i = 0; $i < count($tmpLines); ++$i)
{
if(strlen($tmpLines[ $i ]) > 6 && strlen($tmpLines[ $i ]) < 10)
{
$lines[] = $tmpLines[ $i ];
}
}
$randomWord = $lines[ array_rand($lines) ];
A shorter way, in number of lines, goes like this (but is much less safe):
$randomWord = '';
$lines = file('random.txt');
while(strlen($randomWord) <= 6 || strlen($randomWord) >= 10)
$randomWord = $lines[ array_rand($lines) ];
The first option gets all the lines in the file, and copies only the ones between 6 and 10 chars in length to another array. When choosing a random element from this array, you are "guaranteed" a reasonable access time for any random string.
The second option simply continues to pick a random string until one of the proper length is chosen, but could potentially take a while depending on the random number generator's mood. Unlikely, but I wouldn't want to risk it. Always take reliability as the best approach, in my book.
I would say explode the text file into a variable, run your random generator to get a placement value (position of the random string) then in a loop (a do/while loop), pull the string from the exploded variable, and check it's length to ensure it's what you want
if (strlen($rand_word) > 6 && strlen($rand_word) < 10) {
//execute function and end loop
} else {
// keep checking using a new random placement number
}
The answer depends on the requirement.
If you need to select from a group of strings and only accept one that fits your criteria, then you'll need to use strlen and try again if it is not the correct length.
Otherwise, you're still going to need strlen, to make sure it is at least 6 Chars, but then you can use substr to cut it to 10. If whitespace does not count, use ltrim & rtrim before strlen and substr.
First find all the words that are in the right character range, then pull a random one from the resulting array:
$fileLines = file('somefile.txt');
$myWords = array();
foreach ($fileLines as $line)
{
$thisLine = split(" ",$line);
foreach ($thisLine as $word)
{
$length = strlen($word);
if ($length > 6 && $length < 10)
{
$myWords[] = $word;
}
}
}
$randomWord = $myWords[array_rand($myWords)];
Shortened way!
for ($i=7; $i<=9; $i++)
if (strlen($str) == $i )
echo "bingo! " . strlen($str);

php's preg_match returning different number of matches for same pattern

I'm trying out preg_match with a roman numeral to integer converter. The problem is, for certain inputs, preg_replace seems to be giving too few matches. The code:
function romanNumeralToInt($romanNumeral)
{ preg_match
( '/^(M?M?M?)'
.'((CM)|(CD)|((D?)(C?C?C?)))'
.'((XC)|(XL)|((L?)(X?X?X?)))'
.'((IX)|(IV)|((V?)(I?I?I?)))$/', $romanNumeral, $match);
print_r($match);
$result=0;
$result += 1000*strlen($match[1]);
if(strlen($match[3]) != 0){$result += 900;}
if(strlen($match[4]) != 0){$result += 400;}
if(strlen($match[5]) != 0)
{ $result += 100*strlen($match[7]) + 500*strlen($match[6]);
}
if(strlen($match[9]) != 0){$result += 90;}
if(strlen($match[10]) != 0){$result += 40;}
if(strlen($match[11]) != 0)
{ $result += 10*strlen($match[13]) + 50*strlen($match[12]);
}
if(strlen($match[15]) != 0){$result += 9;}
if(strlen($match[16]) != 0){$result += 4;}
if(strlen($match[17]) != 0)
{ $result += 1*strlen($match[19]) + 5*strlen($match[18]);
}
return $result;
}
echo romanNumeralToInt("XXVIII"); // gives correct results
But any roman numeral ending in "IV" will cut off the last 3 matches ($matches will only contain elements 0-16 rather than the full 0-19), and similarly any roman numeral ending in "IX" will cut off the last 4 matches.
Is this expected behavior, or is my PHP buggy?
I expect this to be expected behavior. =)
Regex tries to match OR groups from left to right, stopping as soon as it finds a match, so it will never try to match those last three (or four) groups if it finds a IV or IX.
Actually, I think that, if your expression contains a CM or XL or something like that, some of the other entries will be missing, too.
I find that using RegExr helps a lot with debugging regular expressions. Using this for your regex, some groups catch empty strings, and some groups contain NO MATCH.

Categories