Truncating a string after x amount of charcters - php

I have a string that that is an unknown length and characters.
I'd like to be able to truncate the string after x amount of characters.
For example from:
$string = "Hello# m#y name # is Ala#n Colem#n"
$character = "#"
$x = 4
I'd like to return:
"Hello# m#y name # is Ala#"
Hope I'm not over complicating things here!
Many thanks

I'd suggest explode-ing the string on #, then getting the 1st 4 elements in that array.
$string = "Hello# m#y name # is Ala#n Colem#n";
$character = "#";
$x = 4;
$split = explode($character, $string);
$split = array_slice($split, 0, $x);
$newString = implode($character, $split).'#';

function posncut( $input, $delim, $x ) {
$p = 0;
for( $i = 0; $i < $x; ++ $i ) {
$p = strpos( $input, $delim, $p );
if( $p === false ) {
return "";
}
++ $p;
}
return substr( $input, 0, $p );
}
echo posncut( $string, $character, $x );
It finds each delimiter in turn (strpos) and stops after the one you're looking for. If it runs out of text first (strpos returns false), it gives an empty string.
Update: here's a benchmark I made which compares this method against explode: http://codepad.org/rxTt79PC. Seems that explode (when used with array_pop instead of array_slice) is faster.

Something along these lines:
$str_length = strlen($string)
$character = "#"
$target_count = 4
$count = 0;
for ($i = 0 ; $i<$str_length ; $i++){
if ($string[$i] == $character) {
$count++
if($count == $target_count) break;
}
}
$result = sub_str($string,0,$i)

Related

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;

How to get substring of comma delimited string?

I have a comma delimited string and want the first 100 entries (not including the 100th comma) as a single string.
So for example if I had the string
a,b,c,d,e,f,g
And the problem was get the first 3 entries, the desired result string would be
a,b,c
Using explode/implode:
$str = 'a,b,c,d,e,f,g';
$temp1 = explode(',',$str);
$temp2 = array_slice($temp1, 0, 3);
$new_str = implode(',', $temp2);
Using regex:
$new_str = preg_replace('/^((?:[^,]+,){2}[^,]+).*$/','\1',$str);
try php's explode() function.
$string_array = explode(",",$string);
Loop through the array to get the values you want:
for($i = 0; $i < sizeof($string_array); $i++)
{
echo $string_array[$i];//display values
}
You can do so by finding the 100th delimiter:
$delimiter = ',';
$count = 100;
$offset = 0;
while((FALSE !== ($r = strpos($subject, $delimiter, $offset))) && $count--)
{
$offset = $r + !!$count;
}
echo substr($subject, 0, $offset), "\n";
or similarly tokenize it:
$delimiter = ',';
$count = 100;
$len = 0;
$tok = strtok($subject, $delimiter);
while($tok !== FALSE && $count--)
{
$len += strlen($tok) + !!$count;
$tok = strtok($delimiter);
}
echo substr($subject, 0, $len), "\n";
One way is to split the string after a comma and put the first 100 indexes together (comma-separated).
Before this you have to check if count(array) is greater or smaller than 100.

cut particular pointed string using php

How I cut the extra 0 string from those sample.
current string: 0102000306
required string: 12036
Here a 0 value have in front of each number. So, i need to cut the extra all zero[0] value from the string and get my expected string. It’s cannot possible using str_replace. Because then all the zero will be replaced. So, how do I do it?
Using a regex:
$result = preg_replace('#0(.)#', '\\1', '0102000306');
Result:
"12036"
Using array_reduce:
$string = array_reduce(str_split('0102000306', 2), function($v, $w) { return $v.$w[1]; });
Or array_map+implode:
implode('',array_map('intval',str_split('0102000306',2)));
$currentString = '0102000306';
$length = strlen($currentString);
$newString = '';
for ($i = 0; $i < $length; $i++) {
if (($i % 2) == 1) {
$newString .= $currentString{$i};
}
}
or
$currentString = '0102000306';
$tempArray = str_split($currentString,2);
$newString = '';
foreach($tempArray as $val) {
$newString .= substr($val,-1);
}
It's not particularly elegant but this should do what you want:
$old = '0102000306';
$new = '';
for ($i = 0; $i < strlen($old); $i += 2) {
$new .= $old[$i+1];
}
echo $new;

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

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 :)

PHP Multiple Occurences Of Words Within A String

I need to check a string to see if any word in it has multiple occurences. So basically I will accept:
"google makes love"
but I don't accept:
"google makes google love" or "google makes love love google" etc.
Any ideas? Really don't know any way to approach this, any help would be greatly appreciated.
Based on Wicked Flea code:
function single_use_of_words($str) {
$words = explode(' ', trim($str)); //Trim to prevent any extra blank
if (count(array_unique($words)) == count($words)) {
return true; //Same amount of words
}
return false;
}
Try this:
function single_use_of_words($str) {
$words = explode(' ', $str);
$words = array_unique($words);
return implode(' ', $words);
}
No need for loops or arrays:
<?php
$needle = 'cat';
$haystack = 'cat in the cat hat';
if ( occursMoreThanOnce($haystack, $needle) ) {
echo 'Success';
}
function occursMoreThanOnce($haystack, $needle) {
return strpos($haystack, $needle) !== strrpos($haystack, $needle);
}
?>
<?php
$words = preg_split('\b', $string, PREG_SPLIT_NO_EMPTY);
$wordsUnique = array_unique($words);
if (count($words) != count($wordsUnique)) {
echo 'Duplicate word found!';
}
?>
The regular expression way would definitely be my choice.
I did a little test on a string of 320 words with Veynom's function and a regular expression
function preg( $txt ) {
return !preg_match( '/\b(\w+)\b.*?\1/', $txt );
}
Here's the test
$time['preg'] = microtime( true );
for( $i = 0; $i < 1000; $i++ ) {
preg( $txt );
}
$time['preg'] = microtime( true ) - $time['preg'];
$time['veynom-thewickedflea'] = microtime( true );
for( $i = 0; $i < 1000; $i++ ) {
single_use_of_words( $txt );
}
$time['veynom-thewickedflea'] = microtime( true ) - $time['veynom-thewickedflea'];
print_r( $time );
And here's the result I got
Array
(
[preg] => 0.197616815567
[veynom-thewickedflea] => 0.487532138824
)
Which suggests that the RegExp solution, as well as being a lot more concise is more than twice as fast. ( for a string of 320 words anr 1000 iterations )
When I run the test over 10 000 iterations I get
Array
(
[preg] => 1.51235699654
[veynom-thewickedflea] => 4.99487900734
)
The non RegExp solution also uses a lot more memory.
So.. Regular Expressions for me cos they've got a full tank of gas
EDIT
The text I tested against has duplicate words, If it doesn't, the results may be different. I'll post another set of results.
Update
With the duplicates stripped out ( now 186 words ) the results for 1000 iterations is:
Array
(
[preg] => 0.235826015472
[veynom-thewickedflea] => 0.2528860569
)
About evens
function Accept($str)
{
$words = explode(" ", trim($str));
$len = count($words);
for ($i = 0; $i < $len; $i++)
{
for ($p = 0; $p < $len; $p++)
{
if ($p != $i && $words[$i] == $words[$p])
{
return false;
}
}
}
return true;
}
EDIT
Entire test script. Note, when printing "false" php just prints nothing but true is printed as "1".
<?php
function Accept($str)
{
$words = explode(" ", trim($str));
$len = count($words);
for ($i = 0; $i < $len; $i++)
{
for ($p = 0; $p < $len; $p++)
{
if ($p != $i && $words[$i] == $words[$p])
{
return false;
}
}
}
return true;
}
echo Accept("google makes love"), ", ", Accept("google makes google love"), ", ",
Accept("google makes love love google"), ", ", Accept("babe health insurance babe");
?>
Prints the correct output:
1, , ,
This seems fairly fast. It would be interesting to see (for all the answers) how the memory usage and time taken increase as you increase the length of the input string.
function check($str) {
//remove double spaces
$c = 1;
while ($c) $str = str_replace(' ', ' ', $str, $c);
//split into array of words
$words = explode(' ', $str);
foreach ($words as $key => $word) {
//remove current word from array
unset($words[$key]);
//if it still exists in the array it must be duplicated
if (in_array($word, $words)) {
return false;
}
}
return true;
}
Edit
Fixed issue with multiple spaces. I'm not sure whether it is better to remove these at the start (as I have) or check each word is non-empty in the foreach.
The simplest method is to loop through each word and check against all previous words for duplicates.
Regular expression with backreferencing
http://www.regular-expressions.info/php.html
http://www.regular-expressions.info/named.html

Categories