Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
how correctly make on php ?
If set range have small letters -> replace them on big.
length of string - const
number of symbols from 0
set range : [4,6]
Example :
17xG2v9Hj5 -> 17xG2V9Hj5
b7qfK5yte9 -> b7qfK5Yte9
My code :
$m = '17xG2v9Hj5';
$s1 = mb_substr($m, 0, 4); // -> 17xG
$s2 = mb_substr($m, 4, 3); // -> 2v9
$ss = ucwords(strtoupper($s2)); // -> 2V9
$s3 = mb_substr($m, 7,3); // -> Hj5
$my = $s1.$ss.$s3; // -> 17xG2V9Hj5
var_dump($m).'<br/>';
var_dump($s1).'<br/>';
var_dump($s2).'<br/>';
var_dump($ss).'<br/>';
var_dump($s3).'<br/>';
var_dump($my).'<br/>';// ??? ['<br/>'] for [var_dump()]
// don't work;
String : [a-z] and [0-9].
It is possible to make more shortly and faster?
Thanks.
I'm really not sure what you're trying to achieve?
var_dump is typically used for debug purposes, its output will be more readable if wrapped in <pre></pre> tags.
var_dump($my).'<br/>';
Will not actually append '<br/>' to the output of var_dump it will append it the the value returned by var_dump, in this case void
ie.
$out = var_dump($my).'<br/>'; //$out == '<br/>'
If you want to output <br/> after var_dump you must echo it separately.
ie.
var_dump($my);
echo '<br/>';
You may use substr_replace to do this in one round (Assuming range and string-length are fixed)
$in = '17xG2v9Hj5';
var_dump(substr_replace($in, mb_strtoupper(mb_substr($in, 4, 3)), 4, 3));
A multibyte variant of the substr_replace function can be found here
Answer below is based on Revision 1 of the question assuming a more general solution is wanted
Naive solution but should work if I understood your question correctly:
<?php
$in = '17xG2v9Hj5';
$range = [4,6];
var_dump(uc_range($in, $range));
function uc_range($string, array $range) {
if(!is_string($string)) {
throw new InvalidArgumentException('$string is supposed to be a string');
}
$chars = str_split_unicode($string);
foreach(range($range[0], $range[1]) as $keyIndex) {
if(isset($chars[$keyIndex])) {
$chars[$keyIndex] = mb_strtoupper($chars[$keyIndex]);
}
}
return implode("", $chars);
}
// see http://www.php.net/manual/en/function.str-split.php#107658
function str_split_unicode($str, $l = 0) {
if ($l > 0) {
$ret = array();
$len = mb_strlen($str, "UTF-8");
for ($i = 0; $i < $len; $i += $l) {
$ret[] = mb_substr($str, $i, $l, "UTF-8");
}
return $ret;
}
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
}
Related
I'm facing an issue with a function that gets a string between two other strings.
function string_between($str, $starting_word, $ending_word) {
$subtring_start = strpos($str, $starting_word);
$subtring_start += strlen($starting_word);
foreach ($ending_word as $a){
$size = strpos($str, $a, $subtring_start) - $subtring_start;
}
return substr($str, $subtring_start, $size);
}
The issue is that the function searches for the first ending_word in the array.
An example will be easier to understand:
$array_a = ['the', 'amen']; // Starting strings
$array_b = [',', '.']; // Ending strings
$str = "Hello, the world. Then, it is over.";
Expected result:
"the world."
Current result:
"the world. Then,"
The function will think that the ending_word is "," because it is the first element met in the array_b. However, the text encounters first the '.' after the "the" starting word.
How can I make sure the function goes through the text and stops at the first element in the $str present in the array_b, whatever the position in the array?
Any idea?
Basically, you need to break outside of your foreach loop when $size > 0
That way it stops looping through your array when it finds the 1st occurrence. Here is the more complete code with other fixes:
function stringBetween($string, $startingWords, $endingWords) {
foreach ($startingWords as $startingWord) {
$subtringStart = strpos($string, $startingWord);
if ($subtringStart > 0) {
foreach ($endingWords as $endingWord){
$size = strpos($string, $endingWord, $subtringStart) - $subtringStart + strlen($endingWord);
if ($size > 0) {
break;
}
}
if ($size > 0) {
return substr($string, $subtringStart, $size);
}
}
}
return null;
}
$startArr = array('the', 'amen'); // Starting strings
$endArr = array('.', ','); // Ending strings
$str = "Hello, the world. Then, it is over.";
echo stringBetween($str, $startArr, $endArr); // the world.
This type of problems are best solved by PCRE regexes, only couple of lines needed in function :
function string_between($str, $starts, $ends) {
preg_match("/(?:{$starts}).*?(?:{$ends})/mi", $str, $m);
return $m[0];
}
Then calling like this :
echo string_between("Hello, the world. Then, it is over.", 'the|amen', ',|\.');
Produces : the world.
The trick,- search to the nearest matching ending symbol is done with regex non-greedy seach, indicated by question symbol in pattern .*?. You can even extend this function to accept arrays as starting/ending symbols, just that case modify function (possibly with implode('|',$arr)) for concatenating symbols into regex grouping formula.
Edited version
This works now. Iterate over your teststrings from first array looking for position of occurance from teststring. If found one then search for the second teststring at startposition from end of first string.
To get the shortest hit I store the position from the second and take the minimum.
You can try it at http://sandbox.onlinephpfunctions.com/code/0f1e5c97da62b4daaf0e49f52271fe288d1cacbb
$array_a =array('the','amen');
$array_b =array(',','.', '#');
$str = "Hello, the world. Then, it is over.";
function earchString($str, $array_a, $array_b) {
forEach($array_a as $test) {
$pos = strpos($str, $test);
if ($pos===false) continue;
$found = [];
forEach($array_b as $test2) {
$posStart = $pos+strlen($test);
$pos2 = strpos($str, $test2, $posStart);
$found[] = ($pos2!==false) ? $pos2 : INF;
}
$min = min($found);
if ($min !== INF)
return substr($str,$pos,$min-$pos) .$str[$min];
}
return '';
}
echo earchString($str, $array_a, $array_b);
With this code:
$guessString = 'KUĆA';
$usedLetters = ['Ć'];
$userLetter = 'Ć';
for ($i = 0; $i < mb_strlen($guessString); $i++) {
$temp = $guessString[$i];
if (in_array($guessString[$i], $usedLetters)) {
echo $guessString[$i];
} else {
echo ' _ ';
}
}
I am trying to compare if $userLetter (that is sent through GET link)
exists in $guessString.
But through debugging:
I finally see that it doesn't read the character right.
It gets "?" instead of "Ć"
So my question is: How to get the correct character with for loop ($guessString[$i])?
Your problem is with
$guessString[$i]
The indexing operator is not multibyte-aware, so it returns the $ith byte of the string. One way to fix this is using mb_substr:
$temp = mb_substr($guessString, $i, 1);
Of course, you should then use $temp everywhere you used $guessString[$i].
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I was trying to make a URL shortener. Where the give url needs to convert to base 62
I have converted the URL in following but it convert it to random number like 0 or 1sromm8 or 2gs0ygibs
base_convert($shortener->full_url, 10, 36);
How do i convert it to base62 so that every time 5 characters unique name generated.
I use this customized function to convert String to base62 String
function b62e($str) {
if(mb_check_encoding($str, 'ASCII')) {
$out = '';
$len = strlen($str);
for($i=0; $i<$len; $i+=8) {
$chunk = substr($str, $i, 8);
$outlen = ceil( strlen($chunk)*8/6 );// 8bit/char in, 6bits/char out, round up
$hex = bin2hex($chunk);// gmp won't convert from binary, so go via hex
$raw = gmp_strval(gmp_init(ltrim($hex, '0'), 16), 62);// gmp doesn't like leading 0s
$out .= str_pad($raw, $outlen, '0', STR_PAD_LEFT);
}
return $out;
}
return false;// unicode chars not supported
}
function b62d($str) {
if(mb_check_encoding($str, 'ASCII')) {
$out = '';
$len = strlen($str);
for ($i=0; $i<$len; $i+=11) {
$chunk = substr($str, $i, 11);
$outlen = floor( strlen($chunk)*6/8 );// 6bit/char in, 8bits/char out, round down
$raw = gmp_strval(gmp_init(ltrim($chunk, '0'), 62), 16);// gmp doesn't like leading 0s
$pad = str_pad($raw, $outlen * 2, '0', STR_PAD_LEFT);// double output length as as we're going via hex (4bits/char)
$out .= pack('H*', $pad);// same as hex2bin
}
return $out;
}
return false;// unicode chars not supported
}
Demo
All credits go to Marcus Bointon, Thanks to Flash Thunder answer
May you also use obfuscator to prevent users decode variables
function obf62rep($which){// make array before translate string
$rep = [];
$str1 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$str2 = 'GHIJKLMNqrstuvwx01OPQRSTUVWXYZhijklmnop23456789abcdefgyzABCDEF';
if($which){// while obfuscate from-->to
$fr = str_split($str1);
$to = $str2;
}else{// while de-obfuscate to-->from
$fr = str_split($str2);
$to = $str1;
}
foreach($fr as $k=>$v){// make array tr-->to
$rep[$v] = $to[$k];
}
return $rep;
}
function obf62e($str){return strtr($str,obf62rep(1));}// translate string = obf
function obf62d($str){return strtr($str,obf62rep(0));}// translate back = deobf
Demo
And then make it more simple to use, like
function ob62e($str){return obf62e(b62e($str));}// encode base62 + obfuscate
function ob62d($str){return b62d(obf62d($str));}// decode base62 + deobfuscate
Sample usage
echo ob62e('test');
$name = ob62e('jhon');
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to create a function that returns TRUE if a string is all lowercase without using any built-in PHP functions. How can I do that?
This is what I was working with, but using ctype_lower.
$string = "string";
if (ctype_lower($string)) {
echo $string . ' is all lowercase letters.';
} else {
echo $string . ' is not all lowercase letters.';
}
Well, if you just want a simple-purpose check, you could just compare the original string with an strtolowerred string. Of course, it won't be foolproof. Like this:
function check_lowercase_string($string) {
return ($string === strtolower($string));
}
$string = 'Hi! I am a string';
var_dump(check_lowercase_string($string)); // false
var_dump(check_lowercase_string('test')); // true
A painful attempt of no functions:
function check_lowercase_string($string) {
$chars = '';
// map all small characters
for($alpha = 'a'; $alpha != 'aa'; $alpha++) { $small[] = $alpha; }
$l = 0; // not strlen() :p
while (#$string[$l] != '') {
$l++;
}
for($i = 0; $i < $l; $i++) { // for each string input piece
foreach($small as $letter) { // for each mapped letter
if($string[$i] == $letter) {
$chars .= $letter; // simple filter
}
}
}
// if they are still equal in the end then true, if they are not, false
return ($chars === $string);
}
var_dump(check_lowercase_string('teSt')); // false
You can either use ctype_lower, which is inbuilt, so you don't want that :c.
But you can use the answer from here. And put together a loop which checks for the first character. If uppercase then return true, and if not, then remove the first character of string and continue like that through the entire string.
I'm looking for a php function which can mask credit card & bank information such as routing number and account numbers. I need to mask many formats, so the existing stack overflow answers don't help me that much.
So for example, if the input is 304-443-2456, the function should return xxx-xxx-2456.
Sometimes the number has dashes, and can be in various lengths.
I'm looking for something generic, that I can extend as needed, preferably a zend framework view helper class.
Some little regex in a function of it own, configuration available:
$number = '304-443-2456';
function mask_number($number, $count = 4, $seperators = '-')
{
$masked = preg_replace('/\d/', 'x', $number);
$last = preg_match(sprintf('/([%s]?\d){%d}$/', preg_quote($seperators), $count), $number, $matches);
if ($last) {
list($clean) = $matches;
$masked = substr($masked, 0, -strlen($clean)) . $clean;
}
return $masked;
}
echo mask_number($number); # xxx-xxx-2456
If the function fails, it will return all masked (e.g. a different seperator, less than 4 digits etc.). Some child-safety build in you could say.
Demo
<?php
function ccmask($cc, $char = '#') {
$pattern = '/^([0-9-]+)([0-9]*)$/U';
$matches = array();
preg_match($pattern, $cc, $matches);
return preg_replace('([0-9])', $char, $matches[1]).$matches[2];
}
echo ccmask('304-443-2456'), "\n";
echo ccmask('4924-7921-9900-9876', '*'), "\n";
echo ccmask('30-43-56', 'x'), "\n";
Outputs:
###-###-2456
****-****-****-9876
xx-xx-56
I use a view helper for that. I tend to avoid Regex though as it always takes me ages to work out what it does, especially if I come back to code after a while.
class Zend_View_Helper_Ccmask
{
public function ccmask($ccNum)
{
$maskArray = explode('-', $ccNum);
$sections = count($maskArray) - 1;
for($i = 0; $i < $sections ; $i++){
$maskArray[$i] = str_replace(array(1,2,3,4,5,6,7,8,9,0), 'x', $maskArray[$i]);
}
return implode('-', $maskArray);
}
}
In your view
echo $this->ccmask('304-443-2456');
//output = xxx-xxx-2456
A good way to look at this is at what won't be masked and outputing xs for everything else. A simple, inexpensive solution is:
function cc_mask( $cc_raw, $unmask_count ){
$cc_masked = '';
for( $i=0; $i < ( strlen( $cc_raw ) - $unmask_count ) ; $i++ ){
//If you want to maintain hyphens and special characters
$char = substr( $cc_raw, $i, 1 );
$cc_masked .= ctype_digit( $char ) ? "*" : $char;
}
$cc_masked .= substr( $cc_raw , -$unmask_count );
return $cc_masked;
}
echo cc_mask("304-443-2456",4);
//Output
***-***-2456
Would be even faster if there was no need to maintain the hyphens and special characters