Grab number left and right of string using PHP for MYSQL - php

I have a MySQL database table column that has a size value in multiple formats where users manually entered different value formats.
Using PHP I need to iterate DB table and process this field to grab a withd and height value from each column when the column value matches into the pattern we create...
Below are 90% of the values in these formats. Many are the same format but with either single or double digit to left or right side of lowercase or capital X
Usung PHP how could I match each string to strip all non numeric characters from the value on the left and right side of the X.
left = width
right side = height
1x1
1X1
1"x1"
12x12
12X12
12"x12"
12"X12"
NULL
'' ,_ empty field
I just need to get these values into a width and height variable in PHP.
If I can grab everything left of lowercase and capital X ad well as right of and strip all non numbers then I think it would work easily
There are other values as well and those one should be ignored as they will not fit the pattern. Below is example of some of those odd values I found so far...
18" channel letters
64x20 x 2
Glass Dimensions: 12"x72"
172.61 cm x 28.46 cm
230.15 cm x 42.07 cm
24x24 Interior Double Sided
These type of values should be ignored so I can manually edit these later

I've written up a function called rough_strip_all that should strip all characters in a string except for those listed. Adding this step may resolve the issue for you, but if it doesn't, you might have to look into recompiling to enable the UTF8 support for PCRE.
<?php
// Strips out all characters except for those in allowed set
function rough_strip_all( $string, $allowed_set = '0123456789x. ' )
{
// Takes the allowed set, splits it into character by character,
// then converts each character in the array to its ASCII value
$allowed_ascii = array_map( function($a) {
return ord( $a );
}, str_split( $allowed_set ) );
$return = '';
for( $i = 0, $ilen = mb_strlen( $string ); $i < $ilen; $i++ )
{
// Check if the ASCII value of current character is in the list of allowed
// ascii characters given. If it is, add it to the return string
$ascii = ord( $string{$i} );
if( in_array( $ascii, $allowed_ascii ) )
{
$return .= $string{$i};
}
}
// Returns the newly compiled string
return $return;
}
// Original string
$string = "Misc text: 35.25”x 21.00” 123 extra text 456";
// Display original string
echo "Original string: {$string}<br />";
// Strips out all characters except the following: '0123456789x. '
$string = rough_strip_all( strtolower( $string ) );
// Strip out all characters except for numbers, letter x, decimal points, and spaces
$string = preg_replace( '/([^0-9x \.])/ui', '', $string );
// Find anything that fits the number X number format (including decimal numbers)
preg_match( '/([0-9]+(\.[0-9]+)?) ?x ?([0-9]+(\.[0-9]+)?)/ui', $string, $values );
// Match found
if( !empty( $values ) )
{
// Set dimensions in easy to read variables
$dimension_a = $values[1];
$dimension_b = $values[3];
// Values returned
echo "Dimension A: {$dimension_a}<br />";
echo "Dimension B: {$dimension_b}<br />";
}
// No match found
else
{
echo "No match found.";
}
?>
This should should also work for the additional outliers you added in as it strips out all non-essential characters first, then attempts to make a match. I've also added some display logic to it so you can see the original string and what each dimension is after its been processed, or a message if there has been no match.

Even easier would be preg_match_all("/[0-9]+/", $string, $matches);
Test cases:
1x1
1\"x1
12X12
Array ( [0] => Array ( [0] => 1 [1] => 1 ) ) Array ( [0] => Array ( [0] => 1 >[1] => 1 ) ) Array ( [0] => Array ( [0] => 12 [1] => 12 ) )

Related

PHP Getting Scores From A File

I have an htm file that holds scores for a game. I need to find each score above a 65, insert those scores and names only into a db and then print the entire file on the page with the high score lines in red. The htm file includes simple text:
<pre>
Thursday Afternoon Pairs Thursday Aft Session February 1, 2018
Scores after 5 rounds Average: 50.0 Section A North-South
Pair Pct Score Section Rank MPs
A B C
5 65.00 65.00 A 1 0.50(A) Joseph - Marlene
1 47.00 47.00 B 2/3 1 0.30(A) Janet - Mina
3 47.00 47.00 A 2/3 0.30(A) Renee - Reichle
</pre>
There is no other tags in the file and the file cannot be modified.
I've only gotten as far as trying to find the highscores and see if I can get those to print. This returns no matches found everytime.
$file = 108911.htm;
$pct = "([1-9][0-9]\.[0-9]{2})";
$highgame_pct = 65;
$contents = file_get_contents($file);
$pattern = preg_quote($pct, '/');
$pattern = "/^.*$pct.*\$/m";
if(preg_match_all($pattern, $contents, $matches) >= $highgame_pct){
echo "Found matches:<br />";
echo implode("<br />\n", $matches[0]);
}
else{
echo "No matches found";
}
preg_match_all returns the number of full pattern matches (which might be zero), or FALSE if an error occurred.
Using similar regex pattern and using callback function to filter array:
# define array filter callback function
function filterArray($value1){
return ($value1 >= 65.00);
}
# read file
$file = "108911.htm";
$contents = file_get_contents($file);
# define regex
$pattern = "/(\d{2}\.\d{2})/m";
# find matches
$val = preg_match_all($pattern, $contents, $matches);
echo "Count of matches = $val\n";
# filter matches array
$filteredArray = array_filter($matches[0], 'filterArray');
# print matched element
if (count($filteredArray) > 0) {
echo "Found matches bigger or equal to 65.00:<br />";
echo implode("<br />\n", $filteredArray);
}
else{
echo "No matches found";
}
Output:
Count of matches = 10
Found matches bigger or equal to 65.00:<br />
65.00<br />
65.00
You still need to modify this to match the "Score" column only.
Like anything, there are a lots of ways to do this, here is one to try:
# Set the threshold
$max = 65;
# This will fetch file to array, trim spaces, then remove empty
# using file() will take the file and automatically turn it to an array
$arr = array_filter(file('108911.htm',FILE_SKIP_EMPTY_LINES),function($v){
return (!empty(trim($v)));
});
# This will iterate and find matched values based on pattern
$file = array_values(array_filter(array_map(function($v) use ($max){
# Find values that match decimal pattern (allows 1 to 3 whole numbers and up to 2 decimal points)
preg_match_all('/[0-9]{1,3}\.[0-9]{1,2}/',$v,$match);
# Checks if there are at least 3 values in matched array
$match = (!empty($match[0]) && count($match[0]) == 3)? $match[0] : false;
# If not, just return empty
if(empty($match))
return false;
# If the second value (Points) is less than the max, return empty
if($match[1] < $max)
return false;
# Get the name value
preg_match('/[\w]+ - [\w]+/',$v,$name);
# Return the points and the name
return [
'points' => $match[1],
'name' => $name[0]
];
},$arr)));
# Here is the raw array. You can loop this now to get the rows to insert
print_r($file);
Gives you:
Array
(
[0] => Array
(
[points] => 65.00
[name] => Joseph - Marlene
)
)

Extracting a substring from a string of random letters

I have string that is random in nature example 'CBLBTTCCBB'. My goal is to count the occurrence of the string CTLBT in the string CBLBTTCCBB. Repetition of letters used for checking is not allowed. For example, once CTLBT is formed, the remaining random letters for the next iteration will be BCCB.
The scenario is that we have scratch card where users can win letters to form the word CTLBT. Based on the records of the user the letters that he won are in a string CBLBTTCCBB that is ordered from left to right based on the purchase of the scratch card.
I thought of using strpos but it seems inappropriate since it uses the exact arrangement of the substring from larger string.
Any thoughts on how to solve this?
Thanks!
Note:
Question is not a duplicate of How to count the number of occurrences of a substring in a string? since the solution posted in the given link is different. substr_count counts the occurrence of a substring from a string that assumes the string is in a correct order in which the substring will be formed.
Probably then instead strpos you can use preg_replace then:
function rand_substr_count($haystack, $needle)
{
$result = $haystack;
for($i=0; $i<strlen($needle); $i++) {
$result = preg_replace('/'.$needle[$i].'/', '', $result, 1);
}
if (strlen($haystack) - strlen($result) == strlen($needle)) {
return 1 + rand_substr_count($result, $needle);
} else {
return 0;
}
}
echo rand_substr_count("CBLBTTCCBB", "CTLBT");
If I understood correctly I would do this (with prints for showing the results):
<?
# The string to test
$string="CBLBTTCCBBTLTCC";
# The winning word
$word="CTLBT";
# Get the letters from the word to use them as unique array keys
$letters=array_unique(str_split($word));
print("Letters needed are:\n".print_r($letters,1)."\n");
# Initialize the work array
$match=array("count" => array(),"length"=> array());
# Iterate over the keys to build the array with the number of time the letter is occuring
foreach ($letters as $letter) {
$match['length'][$letter] = substr_count($word,$letter); #Number of time this letter appears in the winning word
$match['count'][$letter] = floor(substr_count($string,$letter) / $match['length'][$letter]); # count the letter (will be 0 if none present) and divide by the number of time it should appear, floor it so we have integer
}
print("Count of each letter divided by their appearance times:\n".print_r($match['count'],1)."\n");
# Get the minimum of all letter to know the number of times we can make the winning word
$wins = min($match['count']);
# And print the result
print("Wins: $wins\n");
?>
wich output:
Letters needed are:
Array
(
[0] => C
[1] => T
[2] => L
[3] => B
)
Count of each letter divided by their appearance times:
Array
(
[C] => 5
[T] => 2
[L] => 2
[B] => 4
)
Wins: 2
As you wish to count the combination regardless of the order, the minimum count of letter will be the number of times the user win, if one letter is not present, it will be 0.
I let you transform this into a function and clean the print lines you don't wish ;)

Validate TelephoneNumber PHP

I was given a task to validate a telephone number (stored in the var $number) introduced by a user in my website
$number = $_POST["telephone"];
The thing is this validation is quite complex as i must validate the number to see if it is from Portugal. i thought about validating it using all the indicators from Portugal, which are 52: (50 indicators are 3 digits long and 2 indicators are 2 digits long) Example of a number:
254872272 (254 is the indicator)
i also thought about making an array with all the indicators and then with a cycle verificate somehow if the first 2/3 digits are equal to the ones in the array.
what do you guys think? how should i solve this problem?
One way is to use regular expressions with named subpatterns:
$number = 254872272;
$ind = array( 251, 252, 254 );
preg_match( '/^(?<ind>\d{3})(?<rest>\d{6})$/', $number, $match );
if ( isset($match['ind']) && in_array( (int) $match['ind'], $ind, true ) ) {
print_r( $match );
/*
Array
(
[0] => 254872272
[ind] => 254
[1] => 254
[rest] => 872272
[2] => 872272
)
*/
}
Or you can insert indicators directly into regular expression:
preg_match( '/^(?<ind>251|252|254)(?<rest>\d{6})$/', $number, $match );
There's potential REGEX ways of "solving" this, but really, all you need is in_array() with your indicators in an array. For example:
$indicators = array('254', '072', '345');
$numbers = array(
'254872272',
'225872272',
'054872272',
'072872272',
'294872272',
'974872272',
'345872272'
);
while ($number = array_shift($numbers)) {
$indicator = substr($number, 0, 3);
if (in_array($indicator, $indicators)) {
echo "$number is indicated ($indicator).\n";
} else {
echo "$number is NOT indicated ($indicator).\n";
}
}
http://codepad.org/zesUaxF7
This gives:
254872272 is indicated (254).
225872272 is NOT indicated (225).
054872272 is NOT indicated (054).
072872272 is indicated (072).
294872272 is NOT indicated (294).
974872272 is NOT indicated (974).
345872272 is indicated (345).
Also, I use strings instead of integers on purpose, since PHP is going to interpret any numbers that begin with 0 (like 0724445555) as not having a leading zero, so you need to use a string to make sure that works correctly.
Perhaps with a regular expression?
I have not tested the following, but it should check for one of the matching indicators, followed by any 6 digits, something like:
$indicators = array('123' ,'456', '78'); // etc...
$regex = '/^(' . implode('|', $indicators) . ')[0-9]{6}$/';
if(preg_match($regex, 'your test number')) {
// Run further code...
}
There's a couple of libraries around that aim to validate as many telephone number formats as possible against the actual validation format, as defined by the relevant authorities.
They are usually based on a library by Google, and there are versions for PHP.

Padding with %03.3f doesn't work

I have the following function (in PHP):
function FormatSize( $size ) {
$size = intval( $size );
$idx = 0;
$prefixes = array( "", "Ki", "Mi", "Gi", "Ti", "Pi" );
while( $size > 1024 ) {
$size = $size / 1024;
$idx++;
}
return sprintf( "%03.2f %sB", $size, $prefixes[$idx] );
}
and the following in lua
function GetSize( iSize )
local iSizeTemp, sPrefix, i = tonumber(iSize) or 0, {"", "Ki", "Mi", "Gi", "Ti", "Pi"}, 1
while iSizeTemp > 1024 do
iSizeTemp, i = iSizeTemp/1024, i+1
end
return string.format( "%03.2f %sB", iSizeTemp, sPrefix[i] )
end
The return statement uses %03.2f which should return the output as PQR.XY format, where P or Q or both can be zero.
But I'm getting a simple output (the same as %.2f) and the padding part (%03) seems to have no effect whatsoever. Here is the codepad link (for PHP and for Lua) for an example; where I'm passing a number 1285854482 to the function. The output comes to be 1.20 GiB instead of 001.20 GiB.
You seem to misundestand the description of %.f format specification: this - %03.2f - actually means 'allocate at least 3 symbols to represent a number, at least 2 of them for representing its non-integer part'. Note that full stop is not included into this 2 - but is included into 3, so this formatter never actually hits its 'minimum'. )
Change it into '%06.2f', and it'll work as you expect: of 6 symbols, 3 will be spent on a full stop symbol and two digits after, so 3 remain for representing the integer part of the number.
Ah. Found the solution after going through C++ reference on printf, which states about the number succeeding % sign as:
Minimum number of characters to be printed. If the value to be printed
is shorter than this number, the result is padded with blank spaces.
The value is not truncated even if the result is larger.

Change random strings into colours, consistently

I have some IDs that I want to generate random colours for. Making random colours is not the issue, but it has to be consistent.
I could MD5 (or some other kind of hash) the IDs so the code could know how much characters to expect, but the bottomline is it has to generate the same (random) colour for the same ID/hash/string.
All you need for a RGB code is a consistent mapping from your random string to a 6 position hex value. Why not use md5 as a way to a hex string, and then take the first 6 digits?
<?php
function rgbcode($id){
return '#'.substr(md5($id), 0, 6);
}
?>
Here's a simple function that I'm using in one of my own projects to create RGB values which I can use with PHP's imagecolorallocatealpha:
function randomRgbGeneratorFromId( $id = null ) {
$md5 = md5( $id );
$md5 = preg_replace( '/[^0-9a-fA-F]/', '', $md5 );
$color = substr( $md5, 0, 6 );
$hex = str_split( $color, 1 );
$rgbd = array_map( 'hexdec', $hex );
$rgba = array(
( $rgbd[0] * $rgbd[1] ),
( $rgbd[2] * $rgbd[3] ),
( $rgbd[4] * $rgbd[5] ),
);
return $rgba;
}
Of course you can always output to your CSS / HTML by using something like this:
echo sprintf( 'rgb(%s)', implode( ',', randomRgbGeneratorFromId( $id ) ) );
first convert random string into hexadecimal number with 6 digits and remove the floats and make the string into integer and convert them into a hexadecimal string and then put a hash before six digit hexadecimal number and there is a color for that random string and you may find hexadecimal number be more than a six digit one , if so , continue dividing that number with 2 till it becomes 5 digit hexadecimal number and the sixth digit will be the number of time the total hexadecimal number divided by 2, there is your color code.

Categories