I have currency input strings like these.
$50 ...I only need 50
$60.59 ...I only need 60, need to remove $ and .59
€360 ...I only need 360
€36.99 ...I only need 36, need to remove € and .99
£900 ...I only need 900
£90.99 ...I only need 90
In other words, I need to remove all currency symbols from the start of the string and I only need the integer value -- the decimal values can be cut off.
This RegEx should do it
(\$|€|£)\d+
This is even better (thanks to Jan)
[$€£]\d+
Use it with PHP's Preg Match
preg_match — Perform a regular expression match
I would recommend not using a regular expression, as it's overkill for this scenario.
$str = (int)ltrim($str, '$£€');
this is all you need.
Performance vs Regex
I ran the above test through a script to see what the time difference is between my answer and using a RegEx, and on average the RegEx solution was ~20% slower.
<?php
function funcA($a) {
echo (int)ltrim($a, '$£€');
};
function funcB($a) {
echo preg_replace('/^.*?([0-9]+).*$/', '$1', $a);
};
//setup (only run once):
function changeDataA() {}
function changeDataB() {}
$loops = 50000;
$timeA = 0.0;
$timeB = 0.0;
$prefix = str_split('€$€');
ob_start();
for($i=0; $i<$loops; ++$i) {
$a = $prefix[rand(0,2)] . rand(1,999) . '.' . rand(10,99);
$start = microtime(1);
funcA($a);
$timeA += microtime(1) - $start;
$start = microtime(1);
funcB($a);
$timeB += microtime(1) - $start;
}
ob_end_clean();
$timeA = round(1000000 * ($timeA / $loops), 3);
$timeB = round(1000000 * ($timeB / $loops), 3);
echo "
TimeA averaged $timeA microseconds
TimeB averaged $timeB microseconds
";
Timings vary depending on system load, so times should be considered only relative to each other, not compared between executions. Also this isn't a perfect script for performance benchmarking, there are outside influences that can affect these results, but this gives a general idea.
TimeA averaged 5.976 microseconds
TimeB averaged 6.831 microseconds
Use regular expression. Ex:
$toStr = preg_replace('/^.*?([0-9]+).*$/', '$1', $fromStr);
See preg_replace documentation.
use below way
$str = '$50 From here i need only 50
$60.59 From here i need only 60, Need to remove $ and .59
€360 From here i need only 360.
€36.99 From here i need only 36 need to remove € and .99.
£900 From here i need only 900.
£90.99 From here i need only 90.';
$arr_ = array('$','€','£');
echo str_replace($arr_,'',$str);
You could go for:
<?php
$string = <<<DATA
$50 From here i need only 50
$60.59 From here i need only 60, Need to remove $ and .59
€360 From here i need only 360.
€36.99 From here i need only 36 need to remove € and .99.
£900 From here i need only 900.
£90.99 From here i need only 90.
DATA;
# look for one of $,€,£ followed by digits
$regex = '~[$€£]\K\d+~';
preg_match_all($regex, $string, $amounts);
print_r($amounts);
/*
Array
(
[0] => Array
(
[0] => 50
[1] => 60
[2] => 360
[3] => 36
[4] => 900
[5] => 90
)
)
*/
?>
See a demo on ideone.com.
$newString=$string;
$currencyArray = array("$","€","£"); //just add the new item if you want that to add more
foreach($currencyArray as $value)
$newString= str_replace($value,"",$newString);
$newString has what you need.
Related
Is there a term for the idea of storing large numbers as letters? For example let's say I have the (relatively small) number 138201162401719 and I want to shrink the number of characters (I know this does not help with saving disk space) to the fewest possible number of characters. There are 26 letters in the English alphabet (but i count them as 25 since we need a zero letter). If I start splitting up my large number into pieces that are each 25 or less I get:
13, 8, 20, 11, 6, 24, 0, 17, 19
If I then count the numbers of the alphabet a=0, b=1, c=2, d=3... I can convert this to:
NIULGYART
So I went from 15 digits long (138201162401719) to 9 characters long (NIULGYART). This could of course be easily converted back to the original number as well.
So...my first question is "Does this have a name" and my second "Does anyone have PHP code that will do the conversion (in both directions)?"
I am looking for proper terminology so that I can do my own research in Google...though working code examples are cool too.
This only possible if you're considering to store your number before processing as a string. Because you can't store huge number as integers. You will lost the precision (13820116240171986468445 will be stored as 1.3820116240172E+22) so the alot of digits are lost.
If you're considering storing the number as a string this will be your answer:
Functions used: intval, chr and preg_match_all.
<?php
$regex = '/(2[0-5])|(1[0-9])|([0-9])/';
$numberString = '138201162401719';
preg_match_all($regex, $numberString, $numberArray, PREG_SET_ORDER);
echo($numberString . " -> ");
foreach($numberArray as $value){
$character = chr (intval($value[0]) + 65);
echo($character);
}
?>
Demo
This is the result:
138201162401719 -> NIULGYART
Here's how I would do it:
Store the big number as a string and split it into an array of numbers containing one digit each
Loop through the array extract 2-digit chunks using substr()
Check if the number is less than 26 (in which case, it is an alphabet) and add them to an array
Use array_map() with chr() to create a new array of characters from the above array
Implode the resulting array to get the cipher
In code:
$str = '138201162401719';
$arr = str_split($str);
$i = 0; // starting from the left
while ($i < count($arr)) {
$n = substr($str, $i, 2);
$firstchar = substr($n, 0, 1);
if ($n < 26 && $firstchar != 0) {
$result[] = substr($str, $i, 2);
$i += 2; // advance two characters
} else {
$result[] = substr($str, $i, 1);
$i++; // advance one character
}
}
$output = array_map(function($n) {
return chr($n+65);
}, $result);
echo implode($output); // => NIULGYART
Demo.
As an alternative, you could convert the input integer to express it in base 26, instead of base 10. Something like (pseudocode):
func convertBase26(num)
if (num < 0)
return "-" & convertBase26(-num) // '&' is concatenate.
else if (num = 0)
return "A"
endif
output = "";
while (num > 0)
output <- ('A' + num MOD 26) & output // Modulus operator.
num <- num DIV 26 // Integer division.
endwhile
return output
endfunc
This uses A = 0, B = 1, up to Z = 25 and standard place notation: 26 = BA. Obviously a base conversion is easily reversible.
strtr() is a magnificent tool for this task! It replaces the longest match as is traverses the string.
Code: (Demo)
function toAlpha ($num) {
return strtr($num, range("A", "Z"));
}
$string = toAlpha("138201162401719");
echo "$string\n";
$string = toAlpha("123456789012345");
echo "$string\n";
$string = toAlpha("101112131415161");
echo "$string\n";
$string = toAlpha("2625242322212019");
echo "$string";
Output:
NIULGYART
MDEFGHIJAMDEF
KLMNOPQB
CGZYXWVUT
Just flip the lookup array to reverse the conversion: https://3v4l.org/YsFZu
Merged: https://3v4l.org/u3NQ5
Of course, I must mention that there is a vulnerability with converting a sequence of letters to numbers and back to letters. Consider BB becomes 11 then is mistaken for eleven which would traslate to L when converted again.
There are ways to mitigate this by adjusting the lookup array, but that may not be necessary/favorable depending on program requirements.
And here is another consideration from CodeReview.
I have been trying to do the same thing in PHP without success.
Assuming I'm using the 26 letters of the English alphabet, starting with A = 0 down to Z as 25:
I find the highest power of 26 lower than the number I am encoding. I divide it by the best power of 26 I found. Of the result I take away the integer, convert it to a letter and multiply the decimals by 26. I keep doing that until I get a whole number. It's ok to get a zero as it's an A, but if it has decimals it must be multiplied.
For 1 billion which is DGEHTYM and it's done in 6 loops obviously. Although my answer demonstrates how to encode, I'm afraid it does not help doing so on PHP which is what I'm trying to do myself. I hope the algorithm helps people out there though.
I want to format the credit cards like below when i display it,
Eg:
1234 4567 9874 1222
as
1xxx xxxx xxx 1222
Is there any formatting function like this in Yii ?
No - but there's nothing wrong with using straight PHP.
If you always want the 1st and the last 4 chars you can do something like this:
$last4 = substr($cardNum, -4);
$first = substr($cardNum, 0, 1);
$output = $first.'xxx xxxx xxxx '.$last4;
There are many ways to do this, nothing Yii specific
You could do it using str_split (untested):
$string = "1234 4567 1234 456";
$character_array = str_split($string);
for ($i = 1; $i < count($character_array) - 4; $i++) {
if ($character_array[$i] != " "){
$character_array[$i] = "x";
}
}
echo implode($character_array);
So we are creating an array of characters from the string called
$character_array.
We are then looping thru the characters (starting from position 1,
not 0, so the first character is visible).
We loop until the number of entries in the array minus 4 (so the last
4 characters are not replaced) We replace each character in the loop
with an 'x' (if it's not equal to a space)
We the implode the array back into a string
And you could also use preg_replace :
$card='1234 4567 9874 1222';
$xcard = preg_replace('/^([0-9])([- 0-9]+)([0-9]{4})$/', '${1}xxx xxxx xxxx ${3}', $card);
This regex will also take care of hyphens.
There is no in-built function in Yii.
I have
tutorial 1 how to make this
tutorial 21 how to make this
tutorial 2 how to make this
tutorial 3 how to make this
and i need
tutorial 01 how to make this
tutorial 21 how to make this
tutorial 02 how to make this
tutorial 03 how to make this
so i can order them properly. (adding leading 0 when single digit is found)
What would be a php method to convert?
thanks in advance
note-please make sure that it identifies the single digit numbers only first and then add the leading zero
str_pad()
echo str_pad($input, 2, "0", STR_PAD_LEFT);
sprintf()
echo sprintf("%02d", $input);
If it is coming from a DB, this is the way to do it on a sql query:
lpad(yourfield, (select length(max(yourfield)) FROM yourtable),'0') yourfield
This is will get the max value in the table and place the leading zeros.
If it's hardcoded (PHP), use str_pad()
str_pad($yourvar, $numberofzeros, "0", STR_PAD_LEFT);
This is a small example of what I did on a online php compiler, and it works...
$string = "Tutorial 1 how to";
$number = explode(" ", $string); //Divides the string in a array
$number = $number[1]; //The number is in the position 1 in the array, so this will be number variable
$str = ""; //The final number
if($number<10) $str .= "0"; //If the number is below 10, it will add a leading zero
$str .= $number; //Then, add the number
$string = str_replace($number, $str, $string); //Then, replace the old number with the new one on the string
echo $string;
If your goal is to do natural ordering, the way a human being would, why not just use strnatcmp
$arr = [
'tutorial 1 how to make this',
'tutorial 21 how to make this',
'tutorial 2 how to make this',
'tutorial 3 how to make this',
];
usort($arr, "strnatcmp");
print_r($arr);
The above example will output:
Array
(
[0] => tutorial 1 how to make this
[1] => tutorial 2 how to make this
[2] => tutorial 3 how to make this
[3] => tutorial 21 how to make this
)
Here I am faced with an issue that I believe(or at least hope) was solved 1 million times already.
What I got as the input is a string that represents a length of an object in imperial units. It can go like this:
$length = "3' 2 1/2\"";
or like this:
$length = "1/2\"";
or in fact in any other way we normally would write it.
In effort to reduce global wheel invention, I wonder if there is some function, class, or regexp-ish thing that will allow me to convert Imperial length into Metric length?
The Zend Framework has a measurement component for just that purpose. I suggest you check it out - here.
$unit = new Zend_Measure_Length($length,Zend_Measure_Length::YARD);
$unit -> convertTo(Zend_Measure_Length::METER);
Here is my solution. It uses eval() to evaluate the expression, but don't worry, the regex check at the end makes it completely safe.
function imperial2metric($number) {
// Get rid of whitespace on both ends of the string.
$number = trim($number);
// This results in the number of feet getting multiplied by 12 when eval'd
// which converts them to inches.
$number = str_replace("'", '*12', $number);
// We don't need the double quote.
$number = str_replace('"', '', $number);
// Convert other whitespace into a plus sign.
$number = preg_replace('/\s+/', '+', $number);
// Make sure they aren't making us eval() evil PHP code.
if (preg_match('/[^0-9\/\.\+\*\-]/', $number)) {
return false;
} else {
// Evaluate the expression we've built to get the number of inches.
$inches = eval("return ($number);");
// This is how you convert inches to meters according to Google calculator.
$meters = $inches * 0.0254;
// Returns it in meters. You may then convert to centimeters by
// multiplying by 100, kilometers by dividing by 1000, etc.
return $meters;
}
}
So for example, the string
3' 2 1/2"
gets converted to the expression
3*12+2+1/2
which gets evaluated to
38.5
which finally gets converted to 0.9779 meters.
The imperial string values are a little bit more complicated, so I used following expression:
string pattern = "(([0-9]+)')*\\s*-*\\s*(([0-9])*\\s*([0-9]/[0-9])*\")*";
Regex regex = new Regex( pattern );
Match match = regex.Match(sourceValue);
if( match.Success )
{
int feet = 0;
int.TryParse(match.Groups[2].Value, out feet);
int inch = 0;
int.TryParse(match.Groups[4].Value, out inch);
double fracturalInch = 0.0;
if (match.Groups[5].Value.Length == 3)
fracturalInch = (double)(match.Groups[5].Value[0] - '0') / (double)(match.Groups[5].Value[2] - '0');
resultValue = (feet * 12) + inch + fracturalInch;
The regexp would look something like this:
"([0-9]+)'\s*([0-9]+)\""
(where \s represents whitespace - I'm not sure how it works in php). Then you extract the first + second group and do
(int(grp1)*12+int(grp2))*2.54
to convert to centimeters.
I have sets of 5, 6 and 7 digit numbers. I need them to be displayed in the 000/000/000 format. So for example:
12345 would be displayed as 000/012/345
and
9876543 would be displayed as 009/876/543
I know how to do this in a messy way, involving a series of if/else statements, and strlen functions, but there has to be a cleaner way involving regex that Im not seeing.
sprintf and modulo is one option
function formatMyNumber($num)
{
return sprintf('%03d/%03d/%03d',
$num / 1000000,
($num / 1000) % 1000,
$num % 1000);
}
$padded = str_pad($number, 9, '0', STR_PAD_LEFT);
$split = str_split($padded, 3);
$formatted = implode('/', $split);
You asked for a regex solution, and I love playing with them, so here is a regex solution!
I show it for educational (and fun) purpose only, just use Adam's solution, clean, readable and fast.
function FormatWithSlashes($number)
{
return substr(preg_replace('/(\d{3})?(\d{3})?(\d{3})$/', '$1/$2/$3',
'0000' . $number),
-11, 11);
}
$numbers = Array(12345, 345678, 9876543);
foreach ($numbers as $val)
{
$r = FormatWithSlashes($val);
echo "<p>$r</p>";
}
OK, people are throwing stuff out, so I will too!
number_format would be great, because it accepts a thousands separator, but it doesn't do padding zeroes like sprintf and the like. So here's what I came up with for a one-liner:
function fmt($x) {
return substr(number_format($x+1000000000, 0, ".", "/"), 2);
}
Minor improvement to PhiLho's suggestion:
You can avoid the substr by changing the regex to:
function FormatWithSlashes($number)
{
return preg_replace('/^0*(\d{3})(\d{3})(\d{3})$/', '$1/$2/$3',
'0000' . $number);
}
I also removed the ? after each of the first two capture groups because, when given a 5, 6, or 7 digit number (as specified in the question), this will always have at least 9 digits to work with. If you want to guard against the possibility of receiving a smaller input number, run the regex against '000000000' . $number instead.
Alternately, you could use
substr('0000' . $number, -9, 9);
and then splice the slashes in at the appropriate places with substr_replace, which I suspect may be the fastest way to do this (no need to run regexes or do division), but that's really just getting into pointless optimization, as any of the solutions presented will still be much faster than establishing a network connection to the server.
This would be how I would write it if using Perl 5.10 .
use 5.010;
sub myformat(_;$){
# prepend with zeros
my $_ = 0 x ( 9-length($_[0]) ) . $_[0];
my $join = $_[1] // '/'; # using the 'defined or' operator `//`
# m// in a list context returns ($1,$2,$3,...)
join $join, m/ ^ (\d{3}) (\d{3}) (\d{3}) $ /x;
}
Tested with:
$_ = 11111;
say myformat;
say myformat(2222);
say myformat(33333,';');
say $_;
returns:
000/011/111
000/002/222
000;033;333
11111
Back-ported to Perl 5.8 :
sub myformat(;$$){
local $_ = #_ ? $_[0] : $_
# prepend with zeros
$_ = 0 x ( 9-length($_) ) . $_;
my $join = defined($_[1]) ? $_[1] :'/';
# m// in a list context returns ($1,$2,$3,...)
join $join, m/ ^ (\d{3}) (\d{3}) (\d{3}) $ /x;
}
Here's how I'd do it in python (sorry I don't know PHP as well). I'm sure you can convert it.
def convert(num): #num is an integer
a = str(num)
s = "0"*(9-len(a)) + a
return "%s/%s/%s" % (s[:3], s[3:6], s[6:9])
This just pads the number to have length 9, then splits the substrings.
That being said, it seems the modulo answer is a bit better.