php's preg_replace() versus(vs.) ord() - php

What is quicker, for camelCase to underscores;
using preg_replace() or using ord() ?
My guess is the method using ord will be quicker,
since preg_replace can do much more then needed.
<?php
function __autoload($class_name){
$name = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $class_name));
require_once("some_dir/".$name.".php");
}
?>
OR
<?php
function __autoload($class_name){
// lowercase first letter
$class_name[0] = strtolower($class_name[0]);
$len = strlen($class_name);
for ($i = 0; $i < $len; ++$i) {
// see if we have an uppercase character and replace
if (ord($class_name[$i]) > ord('A') && ord($class_name[$i]) < ord('Z')) {
$class_name[$i] = '_' . strtolower($class_name[$i]);
// increase length of class and position
++$len;
++$i;
}
}
return $class_name;
}
?>
disclaimer -- code examples taken from StackOverflowQuestion 1589468.
edit, after jensgram's array-suggestion and finding array_splice i have come up with the following :
<?php
function __autoload ($string)// actually, function camel2underscore
{
$string = str_split($string);
$pos = count( $string );
while ( --$pos > 0 )
{
$lower = strtolower( $string[ $pos ] );
if ( $string[ $pos ] === $lower )
{
// assuming most letters will be underscore this should be improvement
continue;
}
unset( $string[ $pos ] );
array_splice( $string , $pos , 0 , array( '_' , $lower ) );
}
$string = implode( '' , $string );
return $string;
}
// $pos could be avoided by using the array key, something i might look into later on.
?>
When i will be testing these methods i will add this one
but feel free to tell me your results at anytime ;p

i think (and i'm pretty much sure) that the preg_replace method will be faster - but if you want to know, why dont you do a little benchmark calling both functions 100000 times and measure the time?

(Not an answer but too long to be a comment - will CW)
If you're going to compare, you should at least optimize a little on the ord() version.
$len = strlen($class_name);
$ordCurr = null;
$ordA = ord('A');
$ordZ = ord('Z');
for ($i = 0; $i < $len; ++$i) {
$ordCurr = ord($class_name[$i]);
// see if we have an uppercase character and replace
if ($ordCurr >= $ordA && $ordCurr <= $ordZ) {
$class_name[$i] = '_' . strtolower($class_name[$i]);
// increase length of class and position
++$len;
++$i;
}
}
Also, pushing the name onto a stack (an array) and joining at the end might prove more efficient than string concatenation.
BUT Is this worth the optimization / profiling in the first place?

My usecase was slightly different than the OP's, but I think it's still illustrative of the difference between preg_replace and manual string manipulation.
$a = "16 East, 95 Street";
echo "preg: ".test_preg_replace($a)."\n";
echo "ord: ".test_ord($a)."\n";
$t = microtime(true);
for ($i = 0; $i &lt 100000; $i++) test_preg_replace($a);
echo (microtime(true) - $t)."\n";
$t = microtime(true);
for ($i = 0; $i &lt 100000; $i++) test_ord($a);
echo (microtime(true) - $t)."\n";
function test_preg_replace($s) {
return preg_replace('/[^a-z0-9_-]/', '-', strtolower($s));
}
function test_ord($s) {
$a = ord('a');
$z = ord('z');
$aa = ord('A');
$zz = ord('Z');
$zero = ord('0');
$nine = ord('9');
$us = ord('_');
$ds = ord('-');
$toret = '';
for ($i = 0, $len = strlen($s); $i < $len; $i++) {
$c = ord($s[$i]);
if (($c >= $a && $c <= $z)
|| ($c >= $zero && $c <= $nine)
|| $c == $us
|| $c == $ds)
{
$toret .= $s[$i];
}
elseif ($c >= $aa && $c <= $zz)
{
$toret .= chr($c + $a - $aa); // strtolower
}
else
{
$toret .= '-';
}
}
return $toret;
}
The results are
0.42064881324768
2.4904868602753
so the preg_replace method is vastly superior. Also, string concatenation is slightly faster than inserting into an array and imploding it.

If all you want to do is convert camel case to underscores, you can probably write a more efficient function to do so than either ord or preg_replace in less time than it takes to profile them.

I've written a benchmark using the following four functions and I figured out that the one implemented in Magento is the fastest one (it's Test4):
Test1:
/**
* #see: http://www.paulferrett.com/2009/php-camel-case-functions/
*/
function fromCamelCase_1($str)
{
$str[0] = strtolower($str[0]);
return preg_replace('/([A-Z])/e', "'_' . strtolower('\\1')", $str);
}
Test2:
/**
* #see: http://stackoverflow.com/questions/3995338/phps-preg-replace-versusvs-ord#answer-3995435
*/
function fromCamelCase_2($str)
{
// lowercase first letter
$str[0] = strtolower($str[0]);
$newFieldName = '';
$len = strlen($str);
for ($i = 0; $i < $len; ++$i) {
$ord = ord($str[$i]);
// see if we have an uppercase character and replace
if ($ord > 64 && $ord < 91) {
$newFieldName .= '_';
}
$newFieldName .= strtolower($str[$i]);
}
return $newFieldName;
}
Test3:
/**
* #see: http://www.paulferrett.com/2009/php-camel-case-functions/#div-comment-133
*/
function fromCamelCase_3($str) {
$str[0] = strtolower($str[0]);
$func = create_function('$c', 'return "_" . strtolower($c[1]);');
return preg_replace_callback('/([A-Z])/', $func, $str);
}
Test4:
/**
* #see: http://svn.magentocommerce.com/source/branches/1.6-trunk/lib/Varien/Object.php :: function _underscore($name)
*/
function fromCamelCase_4($name) {
return strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $name));
}
Result using the string "getExternalPrefix" 1000 times:
fromCamelCase_1: 0.48158717155457
fromCamelCase_2: 2.3211658000946
fromCamelCase_3: 0.63665509223938
fromCamelCase_4: 0.18188905715942
Result using random strings like "WAytGLPqZltMfHBQXClrjpTYWaEEkyyu" 1000 times:
fromCamelCase_1: 2.3300149440765
fromCamelCase_2: 4.0111720561981
fromCamelCase_3: 2.2800230979919
fromCamelCase_4: 0.18472790718079
Using the test-strings I got a different output - but this should not appear in your system:
original:
MmrcgUmNfCCTOMwwgaPuGegEGHPzvUim
last test:
mmrcg_um_nf_cc_to_mwwga_pu_geg_eg_hpzv_uim
other tests:
mmrcg_um_nf_c_c_t_o_mwwga_pu_geg_e_g_h_pzv_uim
As you can see at the timestamps - the last test has the same time in both tests :)

Related

Reverse string without strrev

Some time ago during a job interview I got the task to reverse a string in PHP without using strrev.
My first solution was something like this:
$s = 'abcdefg';
$temp = '';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$temp .= $s{$length - $i - 1};
}
var_dump($temp);
// outputs string(7) "gfedcba"
then they asked me if I could do this without doubling the memory usage (not using the $temp variable or any variable to copy the reversed string to) and I failed.
This kept bugging me and since then I tried to solve this multiple times but I constantly failed.
My latest try looks like this:
$s = 'abcdefg';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$s = $s{$i * 2} . $s;
}
var_dump($s);
// outputs string(14) "gfedcbaabcdefg"
It's not a solution to chop off "abcdefg" after the loop because then I would still double the amount of memory used. I need to remove the last character in every iteration of the loop.
I tried to use mb_substr like this:
$s = 'abcdefg';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$s = $s{$i * 2} . mb_substr($s, $length - $i - 1, 1);
}
var_dump($s);
but it only gives me Uninitialized string offset errors.
This is where I'm stuck (again). I tried googling but all the solutions I found either echo the characters directly or use a temporary variable.
I also found the Question PHP String reversal without using extra memory but there's no answer that fits my needs.
That's an interesting one.
Here's something I just came up with:
$s = 'abcdefghijklm';
for($i=strlen($s)-1, $j=0; $j<$i; $i--, $j++) {
list($s[$j], $s[$i]) = array($s[$i], $s[$j]);
}
echo $s;
list() can be used to assign a list of variables in one operation. So what I am doing is simply swapping characters (starting with first and last, then second-first and second-last and so on, till it reaches the middle of the string)
Output is mlkjihgfedcba.
Not using any other variables than $s and the counters, so I hope that fits your criteria.
You can use the fact that in PHP a string can be thought of as an array of characters.
Then basically what you want to do is to replace each character $i on the left side of the middle of the string with the character $j on the right side of the middle with the same distance.
For example, in a string of seven characters the middle character is on position 3. The character on position 0 (distance 3) needs to be swapped with the character on position 6 (3 + 3), the character on position 1 (distance 2) needs to be swapped with the character on position 5 (3 + 2), etc.
This algorithm can be implemented as follows:
$s = 'abcdefg';
$length = strlen($s);
for ($i = 0, $j = $length-1; $i < ($length / 2); $i++, $j--) {
$t = $s[$i];
$s[$i] = $s[$j];
$s[$j] = $t;
}
var_dump($s);
$string = 'abc';
$reverted = implode(array_reverse(str_split($string)));
You could use the XOR swap trick.
function rev($str) {
$len = strlen($str);
for($i = 0; $i < floor($len / 2); ++$i) {
$str[$i] = $str[$i] ^ $str[$len - $i - 1];
$str[$len - $i - 1] = $str[$i] ^ $str[$len - $i - 1];
$str[$i] = $str[$i] ^ $str[$len - $i - 1];
}
return $str;
}
print rev("example");
Try this:
$s = 'abcdefg';
for ($i = strlen($s)-1; $i>=0; $i--) {
$s .= $s[$i];
$s[$i] = NULL;
}
var_dump(trim($s));
Here it is PHP7 version of this:
echo "\u{202E}abcdefg"; // outs: gfedcba
PHP strings are kinda-sorta mutable, but due to copy-on-write it's very difficult to modify them in-place without a copy being made. Some of the above solutions work, but only because they're stand-alone; some already fail because they define a function without a pass-by-reference argument. To get the code to actually operate in-place in a larger program, you'd need to pay careful attention to assignments, function arguments, and scopes.
Example:
$string1 = 'abc';
$string2 = $string1;
$string1[0] = 'b';
print("$string1, $string2");
> "abc, bbc"
I suppose that if between initializing the variable and modifying it you only ever used by-reference assignments (&=) and reference arguments (function rev(&$string)) (or assign the string to an object property initially, and then never assign it to any other variable), you might be able to change the original value of the string without making any copies. That's a bit ridiculous, however, and I'd assume that the interviewer who came up with that question didn't know about copy-on-write.
This isn't quite the same as immutability in other languages, by the way, because it applies to arrays too:
$a = [0, 1, 2];
$b = $a;
$b[0] = 1;
print(implode($a).implode($b));
> "012112"
To sum up, all types (except for objects as of PHP5) are assigned with copy-on-write unless you specifically use the &= operator. The assignment doesn't copy them, but unlike most other languages (C, Java, Python...) that either change the original value (arrays) or don't allow write access at all (strings), PHP will silently create a copy before making any changes.
Of course, if you switched to a language with more conventional pointers and also switched to byte arrays instead of strings, you could use XOR to swap each pair of characters in place:
for i = 0 ... string.length / 2:
string[i] ^= string[string.length-1-i]
string[string.length-1-i] ^= string[i]
string[i] ^= string[string.length-1-i]
Basically #EricBouwers answer, but you can remove the 2nd placeholder variable $j
function strrev2($str)
{
$len = strlen($str);
for($i=0;$i<$len/2;$i++)
{
$tmp = $str[$i];
$str[$i] = $str[$len-$i-1];
$str[$len-$i-1] = $tmp;
}
return $str;
}
Test for the output:
echo strrev2("Hi there!"); // "!ereht iH"
echo PHP_EOL;
echo strrev2("Hello World!"); // "!dlroW olleH"
This will go through the list and stop halfway, it swaps the leftmost and rightmost, and works it's way inward, and stops at the middle. If odd numbered, the pivot digit is never swapped with itself, and if even, it swaps the middle two and stops. The only extra memory used is $len for convenience and $tmp for swapping.
If you want a function that doesn't return a new copy of the string, but just edits the old one in place you can use the following:
function strrev3(&$str)
{
$len = strlen($str);
for($i=0;$i<$len/2;$i++)
{
$tmp = $str[$i];
$str[$i] = $str[$len-$i-1];
$str[$len-$i-1] = $tmp;
}
}
$x = "Test String";
echo $x; // "Test String"
strrev3($x);
echo PHP_EOL;
echo $x; // "gnirtS tseT"
Using &$str passes a direct pointer the the string for editing in place.
And for a simpler implementation like #treegardens, you can rewrite as:
$s = 'abcdefghijklm';
$len = strlen($s);
for($i=0; $i < $len/2; $i++) {
list($s[$i], $s[$len-$i-1]) = array($s[$len-$i-1], $s[$i]);
}
echo $s;
It has the similar logic, but I simplified the for-loop quite a bit.
Its Too Simple
//Reverse a String
$string = 'Basant Kumar';
$length = strlen($string);
for($i=$length-1;$i >=0;$i--){
echo $string[$i];
}
Here is my code to solve your problem
<?php
$s = 'abcdefg';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$s = $s{$i}.mb_substr($s,0,$i).mb_substr($s,$i+1);
}
var_dump($s);
?>
You could also use a recursion to reverse the string. Something like this for example:
function reverse($s) {
if(strlen($s) === 1) return $s;
return substr($s, strlen($s)-1) . reverse(substr($s , 0, strlen($s)-1));
}
What you do here is actually returning the last character of the string and then calling again the same function with the substring that contains the initial string without the last character. When you reach the point when your string is just one character then you end the recursion.
You can use this code to reverse a string without using the reserved function in php.
Code:
<?php
function str_rev($y)// function for reversing a string by passing parameters
{
for ($x = strlen($y)-1; $x>=0; $x--) {
$y .= $y[$x];
$y[$x] = NULL;
}
echo $y;
}
str_rev("I am a student");
?>
Output:
tneduts a ma I
In the above code, we have passed the value of the string as the parameter.We have performed the string reversal using for loop.
you could use substr with negative start.
Theory & Explanation
you can start with for loop with counter from 1 to length of string, and call substr inside iteration with counter * -1 (which will convert the counter into negative value) and length of 1.
So for the first time counter would be 1 and by multiplying with -1 will turn it to -1
Hence substr('abcdefg', -1, 1); will get you g
and next iteration substr('abcdefg', -2, 1); will get you f
and substr('abcdefg', -3, 1); will get you e
and so on ...
Code
$str = 'abcdefghijklmnopqrstuvwxyz';
for($i=1; $i <= strlen($str); $i++) {
echo substr($str, $i*-1, 1);
}
In Action: https://eval.in/583208
public function checkString($str){
if(!empty($str)){
$i = 0;
$str_reverse = '';
while(isset($str[$i])){
$strArr[] = $str[$i];
$i++;
}
for($j = count($strArr); $j>= 0; $j--){
if(isset($strArr[$j])){
$str_reverse .= $strArr[$j];
}
}
if($str == $str_reverse){
echo 'It is a correct string';
}else{
echo 'Invalid string';
}
}
else{
echo 'string not found.';
}
}
//Reverse String word by word
$str = "Reverse string word by word";
$i = 0;
while ($d = $str[$i]) {
if($d == " ") {
$out = " ".$temp.$out;
$temp = "";
}
else
$temp .= $d;
$i++;
}
echo $temp.$out;
The following solution is very simple, but it does the job:
$string = 'Andreas';
$reversedString = '';
for($i = mb_strlen($string) - 1; $i >= 0; $i--){
$reversedString .= $string[$i];
}
var_dump($reversedString) then results: string(7) "saerdnA"
<?php
$value = 'abcdefg';
$length_value = strlen($value);
for($i = $length_value-1; $i >=0 ;$i--){
echo $value[$i];
}
?>
you can try this..
$string = "NASEEM";
$total_word = strlen($string);
for($i=0; $i<=$total_word; $i++)
{
echo substr($string,$total_word-$i,1);
}
i have used some built in function but without str_rev function .
<?php
$text = "red";
$arr = str_split($text);
$rev_text = array_reverse($arr);
echo join(" ",$rev_text);
?>
Try This
<?php
$str="abcde";
for($i=strlen($str)-1;$i>=0;$i--){
echo $str[$i];
}
?>
output
edcba
This is my solution to solve this.
$in = 'This is a test text';
$out = '';
// find string length
$len = strlen($in);
// loop through it and print it reverse
for ( $i = $len - 1; $i >=0;$i-- )
{
$out = $out.$in[$i];
}
echo $out;
Reverse string using recursion function.
$reverseString = '';
function Reverse($str, $len)
{
if ($len == 0) {
return $GLOBALS['reverseString'];
} else {
$len--;
$GLOBALS['reverseString'] .= $str[$len];
return Reverse($str, $len);
}
}
$str = 'Demo text';
$len = strlen($str);
echo Reverse($str, $len)
Try this
$warn = 'this is a test';
$i=0;
while(#$warn[$i]){
$i++;}
while($i>0)
{
echo $warn[$i-1]; $i--;
}

How to replace multiple random characters in string with underscore(_) in PHP

I am using codes like "gjhyYhK", "HJjhkeuJ" etc. But want user to show these codes like:
gj_y__K
HJj__e_J
means code will be edited with "_" at random positions in code.
This will do what you want:
$str = "gjhyYhK";
$len = strlen($str);
$num_to_remove = ceil($len * .4); // 40% removal
for($i = 0; $i < $num_to_remove; $i++)
{
$k = 0;
do
{
$k = rand(1, $len);
} while($str[$k-1] == "_");
$str[$k-1] = "_";
}
print $str . "\n";
If you want more underscores, change the value of $underscores. This will guarantee you get how many underscores you want, so long as you want fewer than the length of the string
Try this:
$string=array(
'gjhyYhK',
'HJjhkeuJ'
);
$arr=array();
foreach ($string as $key=>$value) {
$arr[$key]='';
for ($i=1; $i <=strlen($value); $i++) {
if(rand(0,1)){
$arr[$key].=substr($string[$key],$i,1);
}else{
$arr[$key].='_';
}
}
}
var_dump($arr);
you can try below code to get the functionality what you are looking for
<?php
$string = "gjhyYhK";
$percentage = 40;
$total_length = strlen($string);
$number_of_underscore = floor(($percentage / 100) * $total_length); // I have use floor value, you can use ceil() as well
for ($i = 1; $i <= $number_of_underscore; $i++)
{
$random_position = rand(0, strlen($string) - 1); // get the random position of character to be replaced
if (substr($string, $random_position, 1) !== '_') // check if its already replaced underscore (_)
{
$string = preg_replace("/" . (substr($string, $random_position, 1)) . "/", '_', $string, 1); // here preg_replaced use to replace the character only once, (i.e str_replace() will replace all matching characters)
}
else
{
$i--; // else decrement $i for the loop to run one more time
}
}
echo $string;
?>
let me know if any other help needed
$str = "ADFJ";
$strlen = strlen($str);
$newStr = '';
for ($i = 0; $i < $strlen; $i++) {
if ($i == rand(0, $strlen)) {
$newStr .= '_';
} else {
$newStr .= $str[$i];
}
}
echo $newStr;

Optimal function to create a random UTF-8 string in PHP? (letter characters only)

I wrote this function that creates a random string of UTF-8 characters. It works well, but the regular expression [^\p{L}] is not filtering all non-letter characters it seems. I can't think of a better way to generate the full range of unicode without non-letter characters.. short of manually searching for and defining the decimal letter ranges between 65 and 65533.
function rand_str($max_length, $min_length = 1, $utf8 = true) {
static $utf8_chars = array();
if ($utf8 && !$utf8_chars) {
for ($i = 1; $i <= 65533; $i++) {
$utf8_chars[] = mb_convert_encoding("&#$i;", 'UTF-8', 'HTML-ENTITIES');
}
$utf8_chars = preg_replace('/[^\p{L}]/u', '', $utf8_chars);
foreach ($utf8_chars as $i => $char) {
if (trim($utf8_chars[$i])) {
$chars[] = $char;
}
}
$utf8_chars = $chars;
}
$chars = $utf8 ? $utf8_chars : str_split('abcdefghijklmnopqrstuvwxyz');
$num_chars = count($chars);
$string = '';
$length = mt_rand($min_length, $max_length);
for ($i = 0; $i < $length; $i++) {
$string .= $chars[mt_rand(1, $num_chars) - 1];
}
return $string;
}
\p{L} might be catching too much. Try to limit to {Ll} and {LU} -- {L} includes {Lo} -- others.
With PHP7 and IntlChar there is now a better way:
function utf8_random_string(int $length) : string {
$r = "";
for ($i = 0; $i < $length; $i++) {
$codePoint = mt_rand(0x80, 0xffff);
$char = \IntlChar::chr($codePoint);
if ($char !== null && \IntlChar::isprint($char)) {
$r .= $char;
} else {
$i--;
}
}
return $r;
}

Can you help me understand this simple PHP function, please?

I would like to know how this function works so I can re-write it in ColdFusion. I've never programmed in PHP. I think, the function checks if $string is 11 numbers in length.
But how is it doing it?
Why is it using a loop instead of a simple len() function?
I read about str_pad(), and understand it. But what is the function of the loop iteration $i as a third argument? What's it doing?
if($this->check_fake($cpf, 11)) return FALSE;
function check_fake($string, $length)
{
for($i = 0; $i <= 9; $i++) {
$fake = str_pad("", $length, $i);
if($string === $fake) return(1);
}
}
The function is meant to validate a CPF, the Brazilian equivalent of a US SSN #. The CPF is 11 characters in length. Basically, I need to know what it's doing so I can write the function in Coldfusion.
If it's just a length, can't it be if (len(cpf) != 11) return false; ?
Here is the entire code snippet if it interests you:
<?
/*
*# Class VALIDATE - It validates Brazilian CPF/CNPJ numbers
*# Developer: André Luis Cupini - andre#neobiz.com.br
************************************************************/
class VALIDATE
{
/*
*# Remove ".", "-", "/" of the string
*****************************************************/
function cleaner($string)
{
return $string = str_replace("/", "", str_replace("-", "", str_replace(".", "", $string)));
}
/*
*# Check if the number is fake
*****************************************************/
function check_fake($string, $length)
{
for($i = 0; $i <= 9; $i++) {
$fake = str_pad("", $length, $i);
if($string === $fake) return(1);
}
}
/*
*# Validates CPF
*****************************************************/
function cpf($cpf)
{
$cpf = $this->cleaner($cpf);
$cpf = trim($cpf);
if(empty($cpf) || strlen($cpf) != 11) return FALSE;
else {
if($this->check_fake($cpf, 11)) return FALSE;
else {
$sub_cpf = substr($cpf, 0, 9);
for($i =0; $i <=9; $i++) {
$dv += ($sub_cpf[$i] * (10-$i));
}
if ($dv == 0) return FALSE;
$dv = 11 - ($dv % 11);
if($dv > 9) $dv = 0;
if($cpf[9] != $dv) return FALSE;
$dv *= 2;
for($i = 0; $i <=9; $i++) {
$dv += ($sub_cpf[$i] * (11-$i));
}
$dv = 11 - ($dv % 11);
if($dv > 9) $dv = 0;
if($cpf[10] != $dv) return FALSE;
return TRUE;
}
}
}
}
?>
it basically makes sure the number isn't:
11111111111
22222222222
33333333333
44444444444
55555555555
etc...
With comments:
function check_fake($string, $length)
{
// for all digits
for($i = 0; $i <= 9; $i++)
{
// create a $length characters long string, consisting of
// $length number of the number $i
// e.g. 00000000000
$fake = str_pad("", $length, $i);
// return true if the provided CPN is equal
if($string === $fake) return(1);
}
}
In short, it tests to see if the provided string is just the same digit repeated $length times.

How to calculate the hamming distance of two binary sequences in PHP?

hamming('10101010','01010101')
The result of the above should be 8.
How to implement it?
without installed GMP here is easy solution for any same-length binary strings
function HammingDistance($bin1, $bin2) {
$a1 = str_split($bin1);
$a2 = str_split($bin2);
$dh = 0;
for ($i = 0; $i < count($a1); $i++)
if($a1[$i] != $a2[$i]) $dh++;
return $dh;
}
echo HammingDistance('10101010','01010101'); //returns 8
You don't need to implement it because it already exists:
http://php.net/manual/en/function.gmp-hamdist.php
(If you have GMP support)
The following function works with hex strings (equal length), longer than 32 bits.
function hamming($hash1, $hash2) {
$dh = 0;
$len1 = strlen($hash1);
$len2 = strlen($hash2);
$len = 0;
do {
$h1 = hexdec(substr($hash1, $len, 8));
$h2 = hexdec(substr($hash2, $len, 8));
$len += 8;
for ($i = 0; $i < 32; $i++) {
$k = (1 << $i);
if (($h1 & $k) !== ($h2 & $k)) {
$dh++;
}
}
} while ($len < $len1);
return $dh;
}
If you don't have GMP support there is always something like this. Downside it only works on binary strings up to 32 bits in length.
function hamdist($x, $y){
for($dist = 0, $val = $x ^ $y; $val; ++$dist){
$val &= $val - 1;
}
return $dist;
}
function hamdist_str($x, $y){
return hamdist(bindec($x), bindec($y));
}
echo hamdist_str('10101010','01010101'); //8
Try this function:
function hamming($b1, $b2) {
$b1 = ltrim($b1, '0');
$b2 = ltrim($b2, '0');
$l1 = strlen($b1);
$l2 = strlen($b2);
$n = min($l1, $l2);
$d = max($l1, $l2) - $n;
for ($i=0; $i<$n; ++$i) {
if ($b1[$l1-$i] != $b2[$l2-$i]) {
++$d;
}
}
return $d;
}
You can easily code your hamming function with the help of substr_count() and the code provided in this comment on the PHP manual.
/* hamdist is equivilent to: */
echo gmp_popcount(gmp_xor($ham1, $ham2)) . "\n";
Try:
echo gmp_hamdist('10101010','01010101')

Categories