How would you write a short php function to reverse a string. The function must:
have only one argument
not use the built-in function 'strrev' or 'array_reverse'
not a use a looping construct like 'for', 'foreach' or 'while'.
Quickly scanning down, these all look so long!
function rev($str) {
return $str?rev(substr($str,1)).$str[0]:'';
}
Recursive so obviously doesn't work on strings longer than 100 chars.
Since this sounds like homework question I'll tell you how but you code it yourself.
Turn the string into an array with a cast. Then use one of the array sorting functions that takes a user defined sorting function.
function reverseString($string) {
return shell_exec(sprintf('ruby -e \'puts "%s".reverse\'', preg_replace("/\"/", "\\\"", $string)));
}
Recursive solution:
function sr( $txt ){
return $txt[ strlen( $txt ) - 1 ] . ( ( strlen( $txt ) > 1 )?sr( substr( $txt, 0, strlen($txt)-1 ) ):null) ;
}
echo sr( "abc def ghi jklm" );
Explanation:
return $txt[ strlen( $txt ) - 1 ] // return last byte of string
. // concatenate it with:
(( strlen( $txt ) > 1 ) ? // if there are more bytes in string
sr( substr( $txt, 0, strlen( $txt ) - 1 ) // then with reversed string without last letter
: null ); // otherwise with null
To make it work with zero-length string, another conditional expression was added:
return (strlen($txt))? ($txt[ strlen( $txt ) - 1 ] . ( ( strlen( $txt ) > 1 )?sr( substr( $txt, 0, strlen($txt)-1 ) ):null)):"" ;
<?php
// Reversed string and Number
// For Example :
$str = "hello world. This is john duvey";
$number = 123456789;
$newStr = strrev($str);
$newBum = strrev($number);
echo $newStr;
echo "<br />";
echo $newBum;
OUTPUT :
first : yevud nhoj si sihT .dlrow olleh
second: 987654321`enter code here`
Meets all your requirements but works only in PHP 5.3 or higher. Making it work on others is left as homework.
function reverse($str) {
$i=0;
$j=strlen($str)-1;
start:
if($i>=$j) {
goto done;
}
$tmp = $str[$j];
$str[$j--] = $str[$i];
$str[$i++] = $tmp;
goto start;
done:
return $str;
}
function reverse_string($string) {
if($string !== '')
return substr($string, -1).reverse_string(substr($string, 0, strlen($string)-2));
}
A recursive solution. Feels like something like that is what your teacher is looking for.
function my_strrev ($str) {
$length = strlen($str);
switch ($length) {
case 0: return '';
case 1: return $str; break;
case 2: return $str[1] . $str[0];
default :
return $str[$length-1] . my_strrev(substr($str,1,-1)) . $str[0];
break;
}
}
It swaps the first and the last letter and than makes the same with the rest of the string.
Update:
Inspired by mateusza I created another solution (its fun ;))
function my_strrev2 ($str) {
return $str
? my_strrev2(substr($str, 1)) . $str[0]
: '';
}
It works similar to mateuszas, but this one appends the first character, instead of prepend the last one.
My answer is OOP and uses recursion. Takes care by itself of the recursion limit.
class StringReverser
{
public $reversed_string;
public function __construct ($string) {
$original_recursion_limit = ini_get('pcre.recursion_limit');
$array = str_split($string);
krsort($array);
$i = strlen($string);
ini_set('pcre.recursion_limit', $i+1);
$this->add2string($string, $i, $array);
ini_set('pcre.recursion_limit', $original_recursion_limit);
}
public function reverse() {
return $this->reversed_string;
}
private function add2string ($s, $i, $a) {
if($i) {
$i--;
$this->reversed_string .= $a[$i];
$this->add2string($s, $i,$a, $this->reversed_string);
}
}
}
$string = "Elzo Valugi";
echo $string ."<br>";
$reverser = new StringReverser($string);
echo $reverser->reverse();
<?php
$string="jomon is name my";
for($i=strlen($string);$i>=0;$i--)
{
$char.=$string{$i};
}
echo $char."<br/>";
for($i=0; $i<strlen($char);$i++)
{
if($char[$i+1]==" " || $char[$i+1]=="")
{
for($temp=$i; $temp>=0 && $char[$temp]!=' '; $temp--)
echo $char[$temp];
}
echo " ";
}
?>
Related
I have created for code to check if its palindrome. Now if the string is not a palindrome I want it to be reversed.Can it be done using one conditional loop?
My php code:
class user{
public function __construct() {
if ($this->String_Rev()) {
echo 'Yes, palindrome';
} else {
echo 'not palindrome';
}
}
public function String_Rev() {
$str = "abba";
$i = 0;
while ($str[$i] == $str[strlen($str) - ($i + 1)]) {//Incrementing and decrementing the values in the string at the same time/
$i++;
if ($i > strlen($str)/ 2) {//If the i goes ahead of half of its string then return true and stop its execution.
return 1;
}
}
return 0;
}
}
$obj = new user();
Strings in PHP are not arrays, but you can select the character index of a string just like an array key, which makes the following possible:
<?php
$string = 'foobar';
$string_array = array();
//make an actual array of the characters first
//if you want this to be an object, do this part in your constructor,
//and assign this variable to an object property to work with.
for ($i=0; $i < strlen($string); $i++)
{
$string_array[$i] = $string[$i];
}
echo implode( $string_array ); //prints 'foobar'
echo '<br>' . PHP_EOL;
echo implode( array_reverse( $string_array ) ); //prints 'raboof'
You could easily simplify your palindrome logic by doing this:
//in your case, this would probably be it's own method,
//using the aforementioned class property made in the constructor
$is_palindrome = implode( $string_array ) === implode( array_reverse( $string_array ) );
I don't want to echo string if before string is similar to current string. Let's say our strings are,
$strings = array("software","software","game","antivirus");
My difference function,
function ($val1,$val2) {
similar_text($val1,$val2,$percent);
if ($percent>83) {
// should not echo. But don't know how to do.
}
}
But I don't know how can I do it. I guess it should be with using for each.
Try something like this:
$strings = array("software","software","game","antivirus");
$lastString = '';
foreach ($strings as $string) {
similar_text($lastString, $string, $percent);
if ($percent < 83) {
echo "$string<br />";
$lastString = $string;
}
}
If you don't understand some part of it, leave a comment and I will clarify.
Edit:
I moved the $lastString = $string; inside the condition.
Consider the following list of strings:
$strings = array("software","sofware","sofwart","ofwart","fwart","wart","warts");
Leaving the $lastString assignment outside of the loop would only print software even though lots of the words are very very different software they are not so different from the previous word.
Moving it inside actually gives the output :
software
sofwart
wart
$strings = array("software","software","game","antivirus");
$previous = '';
foreach ($strings as $string) {
if ($string===$previous) {
continue;
} else {
echo $string;
$previous = $string;
}
}
But I think it's better to do it with for like this (it should be faster):
$strings = array("software","software","game","antivirus");
$num = count($strings);
for ($i=0;$i<$num;$i++) {
if ($strings[$i]===$strings[$i-1] && $i!==0) {
continue;
} else {
echo $strings[$i];
}
}
Btw I totally did't get what the $percent means..
An approach using array_filter() (assumes >= 5.3):
$strings = array('software', 'software', 'game', 'antivirus');
$filtered = array_filter($strings, function($curr) {
static $prev;
similar_text($prev, $curr, $percent);
$prev = $curr;
if ($percent < 83) {
return $curr;
}
});
print_r($filtered);
Yields:
Array
(
[0] => software
[2] => game
[3] => antivirus
)
Hope this helps. Actually, I never knew about similar_text() until now. Pretty interesting function. Thanks :)
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
Can someone help me with algorithm for finding the position of the first occurrence of any number in a string?
The code I found on the web does not work:
function my_offset($text){
preg_match('/^[^\-]*-\D*/', $text, $m);
return strlen($m[0]);
}
echo my_offset('[HorribleSubs] Bleach - 311 [720p].mkv');
The built-in PHP function strcspn() will do the same as the function in Stanislav Shabalin's answer when used like so:
strcspn( $str , '0123456789' )
Examples:
echo strcspn( 'That will be $2.95 with a coupon.' , '0123456789' ); // 14
echo strcspn( '12 people said yes' , '0123456789' ); // 0
echo strcspn( 'You are number one!' , '0123456789' ); // 19
HTH
function my_offset($text) {
preg_match('/\d/', $text, $m, PREG_OFFSET_CAPTURE);
if (sizeof($m))
return $m[0][1]; // 24 in your example
// return anything you need for the case when there's no numbers in the string
return strlen($text);
}
function my_ofset($text){
preg_match('/^\D*(?=\d)/', $text, $m);
return isset($m[0]) ? strlen($m[0]) : false;
}
should work for this. The original code required a - to come before the first number, perhaps that was the problem?
I can do regular expressions but I have to go into an altered state to
remember what it does after I've coded it.
Here is a simple PHP function you can use...
function findFirstNum($myString) {
$slength = strlen($myString);
for ($index = 0; $index < $slength; $index++)
{
$char = substr($myString, $index, 1);
if (is_numeric($char))
{
return $index;
}
}
return 0; //no numbers found
}
Problem
Find the first occurring number in a string
Solution
Here is a non regex solution in javascript
var findFirstNum = function(str) {
let i = 0;
let result = "";
let value;
while (i<str.length) {
if(!isNaN(parseInt(str[i]))) {
if (str[i-1] === "-") {
result = "-";
}
while (!isNaN(parseInt(str[i])) && i<str.length) {
result = result + str[i];
i++;
}
break;
}
i++;
}
return parseInt(result);
};
Example Input
findFirstNum("words and -987 555");
Output
-987
Is there a built in function in PHP that would combine 2 strings into 1?
Example:
$string1 = 'abcde';
$string2 = 'cdefg';
Combine to get: abcdefg.
If the exact overlapping sequence and the position are known, then it is possible to write a code to merge them.
TIA
I found the substr_replace method to return funny results.
Especially when working with url strings. I just wrote this function.
It seems to be working perfectly for my needs.
The function will return the longest possible match by default.
function findOverlap($str1, $str2){
$return = array();
$sl1 = strlen($str1);
$sl2 = strlen($str2);
$max = $sl1>$sl2?$sl2:$sl1;
$i=1;
while($i<=$max){
$s1 = substr($str1, -$i);
$s2 = substr($str2, 0, $i);
if($s1 == $s2){
$return[] = $s1;
}
$i++;
}
if(!empty($return)){
return $return;
}
return false;
}
function replaceOverlap($str1, $str2, $length = "long"){
if($overlap = findOverlap($str1, $str2)){
switch($length){
case "short":
$overlap = $overlap[0];
break;
case "long":
default:
$overlap = $overlap[count($overlap)-1];
break;
}
$str1 = substr($str1, 0, -strlen($overlap));
$str2 = substr($str2, strlen($overlap));
return $str1.$overlap.$str2;
}
return false;
}
Usage to get the maximum length match:
echo replaceOverlap("abxcdex", "xcdexfg"); //Result: abxcdexfg
To get the first match instead of the last match call the function like this:
echo replaceOverlap("abxcdex", "xcdexfg", “short”); //Result: abxcdexcdexfg
To get the overlapping string just call:
echo findOverlap("abxcdex", "xcdexfg"); //Result: array( 0 => "x", 1 => "xcdex" )
It's possible using substr_replace() and strcspn():
$string1 = 'abcde';
$string2 = 'cdefgh';
echo substr_replace($string1, $string2, strcspn($string1, $string2)); // abcdefgh
No, there is no builtin function, but you can easily write one yourself by using substr and a loop to see how much of the strings that overlap.