I have this function:
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);
}
When I execute like this:
$arr = str_split_unicode('你好,我将于2014年11月11日变成霸王龙,这非常的好看呢!一二三四五六七八九!', 21);
echo '<pre>';print_r($arr);
The result is:
Array
(
[0] => 你好,我将于2014年11月11日变成霸王
[1] => 龙,这非常的好看呢!一二三四五六七八九!
)
This is not what I want. Because the Arabic number is count as 1 for 1, I hope to count 2 Arabic number as 1, how could I achieve this?
I'm going out on a limb here and will guess that you're actually trying to achieve a uniform block layout in which all characters line up in columns. For this purpose, you should rather use full width numerals ("zen-kaku") instead of trying to align them with 2-for-1:
echo mb_convert_kana('你好,我将于2014年11月11日变成霸王龙...', 'AS', 'UTF-8');
http://php.net/mb_convert_kana
I assume you wanted the number of numbers in the string
Could this be the answer?
$str = '你好,我将于2014年11月11日变成霸王龙,这非常的好看呢!一二三四五六七八九!';
preg_match_all("/\d+/", $str, $output_array);
echo count($output_array[0]); //number of digits in a string. in this case 3
Related
I want to iterate a string in the manner that after each character there should be a space and there will be new string(word) as per the main string character count.
For example
If I put the string "v40eb" as an input. Then Output be something like below.
v 40eb
v4 0eb
v40 eb
v40e b
OR
In Array form like below.
[0]=>v 40eb[1]=>v4 0eb[2]=>v40 eb[3]=>v40e b
I am using PHP.
Thanks
Well, you can divide the process of putting a space into 2 parts.
Get first part of the substring, append a space.
Get second part of the substring and join them together.
Use substr() to get a substring of a string.
Snippet:
<?php
$str = "v40eb";
$result = [];
$len = strlen($str);
for($i=0;$i<$len;++$i){
$part1 = substr($str,0,$i+1);
if($i < $len-1) $part1 .= " ";
$part2 = substr($str,$i+1);
$result[] = $part1 . $part2;
}
print_r($result);
Demo: https://3v4l.org/XGN0a
You could simply loop over the char positions and use substr to get the two parts for each:
$input = 'v40eb';
$combinations = [];
for ($charPos = 1, $charPosMax = strlen($input); $charPos < $charPosMax; $charPos++) {
$combinations[] = substr($input, 0, $charPos) . ' ' . substr($input, $charPos);
}
print_r($combinations);
Demo: https://3v4l.org/EeT1V
$input = 'v40eb';
for($i = 1; $i< strlen($input); $i++) {
$array = str_split($input);
array_splice($array, $i, 0, ' ');
$output[] = implode($array);
}
print_r($output);
Dont forget to check the codec. You might use mb_-prefix to use the multibyte-functions.
Let’s say I have the string http://www.example.com/images/[1-12].jpg. I would like to expand it into:
http://www.example.com/images/1.jpg
http://www.example.com/images/2.jpg
http://www.example.com/images/3.jpg
http://www.example.com/images/4.jpg
http://www.example.com/images/5.jpg
http://www.example.com/images/6.jpg
http://www.example.com/images/7.jpg
http://www.example.com/images/8.jpg
http://www.example.com/images/9.jpg
http://www.example.com/images/10.jpg
http://www.example.com/images/11.jpg
http://www.example.com/images/12.jpg
Here is my code:
$str = "http://www.example.com/images/[1-12].jpg";
while(preg_match_all("/^([^\\[\\]]*)\\[(\\d+)\\-(\\d+)\\](.*)$/m", $str, $mat)){
$arr = array();
$num = sizeof($mat[0]);
for($i = 0; $i < $num; $i++){
for($j = $mat[2][$i]; $j <= $mat[3][$i]; $j++){
$arr[] = rtrim($mat[1][$i].$j.$mat[4][$i]);
}
}
$str = implode(PHP_EOL, $arr);
}
It works fine even if I change $str to a more complex expression like the following:
$str = "http://www.example.com/images/[1-4]/[5-8]/[9-14].jpg";
But, unfortunately, zero-padded integers are not supported. So, if I begin with:
$str = "http://www.example.com/images/[001-004].jpg";
Expected result:
http://www.example.com/images/001.jpg
http://www.example.com/images/002.jpg
http://www.example.com/images/003.jpg
http://www.example.com/images/004.jpg
And the actual result:
http://www.example.com/images/001.jpg
http://www.example.com/images/2.jpg
http://www.example.com/images/3.jpg
http://www.example.com/images/4.jpg
How to change this behaviour so that my code produces the expected result? Also, what are the other shortcomings of my code? Should I really do it with the while loop and preg_match_all or are there faster alternatives?
UPDATE: Changing the seventh line of my code into
$arr[] = rtrim($mat[1][$i].str_pad($j, strlen($mat[2][$i]), 0, STR_PAD_LEFT).$mat[4][$i]);
seems to do the trick. Thanks a lot to sjagr for suggesting this. My question is still open because I would like to know the shortcomings of my code and faster alternatives (if any).
Per #SoumalyoBardhan's request, my suggestion/answer:
If you use str_pad(), you can force the padding based on the size of the matched string using strlen() found by your match. Your usage of it looks good to me:
$arr[] = rtrim($mat[1][$i].str_pad($j, strlen($mat[2][$i]), 0, STR_PAD_LEFT).$mat[4][$i]);
I really can't see what else could be improved with your code, although I don't exactly understand how preg_match_all would be used in a while statement.
A faster alternative with preg_split which also supports descending order (FROM > TO):
$str = "http://www.example.com/images/[12-01].jpg";
$spl = preg_split("/\\[([0-9]+)-([0-9]+)\\]/", $str, -1, 2);
$size = sizeof($spl);
$arr = array("");
for($i = 0; $i < $size; $i++){
$temp = array();
if($i%3 == 1){
$range = range($spl[$i], $spl[$i+1]);
$len = min(strlen($spl[$i]), strlen($spl[++$i]));
foreach($arr as $val){
foreach($range as $ran){
$temp[] = $val.str_pad($ran, $len, 0, 0);
}
}
}
else{
foreach($arr as $val){
$temp[] = $val.$spl[$i];
}
}
$arr = $temp;
}
$str = implode(PHP_EOL, $arr);
print($str);
It has the following result:
http://www.example.com/images/12.jpg
http://www.example.com/images/11.jpg
http://www.example.com/images/10.jpg
http://www.example.com/images/09.jpg
http://www.example.com/images/08.jpg
http://www.example.com/images/07.jpg
http://www.example.com/images/06.jpg
http://www.example.com/images/05.jpg
http://www.example.com/images/04.jpg
http://www.example.com/images/03.jpg
http://www.example.com/images/02.jpg
http://www.example.com/images/01.jpg
After watching my brother cheating in an iphone game like scrabble I was wondering what was the algotithm behing it.
Given some letters: A B C T E E
And SQL table full of correct words.
How would I create all combinations of letters for making afterwars a select like:
Select * from words where word IN ('A','AT',...), just to take from those combinations the ones that are correct ?¿
Another possible way could be a SQL table with every letter in a column for each word.
But afterwards the system should verify that any word form the select has more time the same letter given.
Ex:
c1 c2 c3 c4
t e e
a i r
This question is just for feeding curiosity, and learning witch algorithm it might be used in for creating all those combinations (with full and partial given letters) to check afterwards if they exist.
Thanks!
font: http://icon.cat/worder/wordsfinder
To find all possible valid word this are the following steps
Find all possible combination
Find each permutation for each word in the combination
Search Database for the words
List the words
Script
$tiles = array( "A", "B", "C", "T", "E", "E") ;
$words = array();
$set = powerSet($tiles,2);
$mysql = new mysqli("localhost","root","","word");
$sql = "SELECT id from dic WHERE word = '%s'" ;
foreach ($set as $key => $value)
{
$word = implode("", $value);
$wordPermutation = permute($word);
foreach($wordPermutation as $keyWord)
{
if(!in_array($keyWord, $words))
{
//if($result = $mysql->query(sprintf($sql,$keyWord)))
//{
//var_dump(sprintf($sql,$keyWord));
//if($result->num_rows > 0)
//{
$words[] = $keyWord ;
//}
//}
}
}
}
print_r($words);
Functions
function powerSet($in, $minLength = 1, $max = 10) {
$count = count ( $in );
$members = pow ( 2, $count );
$return = array ();
for($i = 0; $i < $members; $i ++) {
$b = sprintf ( "%0" . $count . "b", $i );
$out = array ();
for($j = 0; $j < $count; $j ++) {
if ($b {$j} == '1')
$out [] = $in [$j];
}
if (count ( $out ) >= $minLength && count ( $out ) <= $max) {
$return [] = $out;
}
}
return $return;
}
function permute($str) {
if (strlen($str) < 2) {
return array($str);
}
$permutations = array();
$tail = substr($str, 1);
foreach (permute($tail) as $permutation) {
$length = strlen($permutation);
for ($i = 0; $i <= $length; $i++) {
$permutations[] = substr($permutation, 0, $i) . $str[0] . substr($permutation, $i);
}
}
return $permutations;
}
Please note that i commented out the database verification section so that the demo can work
See Demo
http://codepad.viper-7.com/oG6E6w
I would try something like
WHERE (word like '%A%' and not word like '%A%A%')
AND (word like '%B%' and not word like '%B%B%')
and so on. But I'm sure there must be more professional solutions!
I finally got it working.
If someone is ever interested on making a self word generator, this is how I made it.
MySQL, a table with:
[id] , [Word]
a view for each length:
V1 = Select Word from TABLE where LENGTH(Word) = 1
V2 = Select Word from TABLE where LENGTH(Word) = 2
[...]
php side:
Using the functions of baba, I made an array where: array[2] are the combinations of letters that have a length of 2, and so on.
Finally all i had to do is a Select for each array to the view like
Select Word from V3 where Word like ('asd','dsa',....);
There must be a faster way, but with a less than a second (localhost) and word diccionary of 700K made its way.
A better way to achieve unscrambling is to use anagrams. So instead of having a library of all the possible words, use an associative array using the letters that make up the words as the index.
anagram['aer'] = ['are', 'ear', 'era']
To implement this, loop through all of your dictionary words and push each one into an array where the index is the letters of the word in alphabetical order.
for(var i = 0; i < dictionary.length; i++) {
//Loop through dictionary array
var str = words[i].split('').sort().join('');
//break apart the word and sort it alphabetically
if(!anagram[str]) {
//check if there is already an index with that same anagram
anagram[str] = [];
}
anagram[str].push(words[i]);
//Add the word to the anagram array
}
This way allows you to quickly index the library without going through thousands of possible permutations.
An example of this method in javascript: Word Unscrambler
Here is great article about World fastest scrabble program
You just should have some knowledge in Descrete Math(Word Automats). Hope it will help you :)
I have a string like this "0011100001100111", and i would like to know the length of each sequence (00, 111, 0000, 11, 00, 111), in the right order.
How can I do that in PHP ?
Thanks to who will help me.
create a loop that loops through the entire string. It would look at each character in the string and compare it to the previous character. If it is the same, then it increases a counter, if it is different, it pushes the counter value onto an array and clears the counter.
Untested code:
function countSequenceLengths($str){
$counter = 1;
$lastChar = $str[0];
$ret = array();
for($i=1; $i<=strlen($str); $i++){
if($i<strlen($str) && $str[$i] == $lastChar){
$counter++;
}else{
$ret[] = $counter;
$counter = 1;
$lastChar = $str[$i];
}
}
return $ret;
}
You could use a regular expression to do that:
preg_split('/(?<=(.))(?!\\1)/', $str)
Here you’re getting an additional empty string at the end that you just need to remove:
array_slice(preg_split('/(?<=(.))(?!\\1)/', $str), 0, -1)
The code I made, with your help :
$string = "1111100111111001111110011111100111111001111... ...10011111100111111001";
$str = substr($string, 10, 12);
echo "str = '".$str."'<br />";
$array = array_slice(preg_split('/(?<=(.))(?!\\1)/', $str), 0, -1);
for($i=0; $i<count($array); $i++){
echo "array[".$i."] = '".$array[$i]."', ";
echo "array[".$i."] length = '".strlen($array[$i])."'<br />";
}
returns me the values I needed :
str = '111001111110'
array[0] = '111', array[0] length = '3'
array[1] = '00', array[1] length = '2'
array[2] = '111111', array[2] length = '6'
array[3] = '0', array[3] length = '1'
Thanks a lot !
Say I have a string of 16 numeric characters (i.e. 0123456789012345) what is the most efficient way to delimit it into sets like : 0123-4567-8901-2345, in PHP?
Note: I am rewriting an existing system that is painfully slow.
Use str_split():
$string = '0123456789012345';
$sets = str_split($string, 4);
print_r($sets);
The output:
Array
(
[0] => 0123
[1] => 4567
[2] => 8901
[3] => 2345
)
Then of course to insert hyphens between the sets you just implode() them together:
echo implode('-', $sets); // echoes '0123-4567-8901-2345'
If you are looking for a more flexible approach (for e.g. phone numbers), try regular expressions:
preg_replace('/^(\d{4})(\d{4})(\d{4})(\d{4})$/', '\1-\2-\3-\4', '0123456789012345');
If you can't see, the first argument accepts four groups of four digits each. The second argument formats them, and the third argument is your input.
This is a bit more general:
<?php
// arr[string] = strChunk(string, length [, length [...]] );
function strChunk() {
$n = func_num_args();
$str = func_get_arg(0);
$ret = array();
if ($n >= 2) {
for($i=1, $offs=0; $i<$n; ++$i) {
$chars = abs( func_get_arg($i) );
$ret[] = substr($str, $offs, $chars);
$offs += $chars;
}
}
return $ret;
}
echo join('-', strChunk('0123456789012345', 4, 4, 4, 4) );
?>