I have text which is generated by print_r($some_array,true) and it looks something like this:
Array
(
[name] => Jon
[lastname] => Jonson
[car] => Array
(
[name] => bmw
[year] => 2012
)
)
(Real data have much more values and more dimensions.)
Question: how to convert this data back, into php's array ?
Looking at the print_r documentation on php.net 'Matt' has posted a solution:
<?php
function print_r_reverse($in) {
$lines = explode("\n", trim($in));
if (trim($lines[0]) != 'Array') {
// bottomed out to something that isn't an array
return $in;
} else {
// this is an array, lets parse it
if (preg_match("/(\s{5,})\(/", $lines[1], $match)) {
// this is a tested array/recursive call to this function
// take a set of spaces off the beginning
$spaces = $match[1];
$spaces_length = strlen($spaces);
$lines_total = count($lines);
for ($i = 0; $i < $lines_total; $i++) {
if (substr($lines[$i], 0, $spaces_length) == $spaces) {
$lines[$i] = substr($lines[$i], $spaces_length);
}
}
}
array_shift($lines); // Array
array_shift($lines); // (
array_pop($lines); // )
$in = implode("\n", $lines);
// make sure we only match stuff with 4 preceding spaces (stuff for this array and not a nested one)
preg_match_all("/^\s{4}\[(.+?)\] \=\> /m", $in, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
$pos = array();
$previous_key = '';
$in_length = strlen($in);
// store the following in $pos:
// array with key = key of the parsed array's item
// value = array(start position in $in, $end position in $in)
foreach ($matches as $match) {
$key = $match[1][0];
$start = $match[0][1] + strlen($match[0][0]);
$pos[$key] = array($start, $in_length);
if ($previous_key != '') $pos[$previous_key][1] = $match[0][1] - 1;
$previous_key = $key;
}
$ret = array();
foreach ($pos as $key => $where) {
// recursively see if the parsed out value is an array too
$ret[$key] = print_r_reverse(substr($in, $where[0], $where[1] - $where[0]));
}
return $ret;
}
}
?>
(Not my code)
Related
I have a plan to make search from txt file that I prepare, the txt file content similar like this below
a.txt
Amy Jefferson
Nathalie Johnson
Emma West
Donna Jefferson
Tanya Nathalie
George West
Emma Watson
Emma Jefferson
If the code was like this
a.php
$filename = "a.txt";
$example = file($filename, FILE_IGNORE_NEW_LINES);
$searchword = 'Emma Jefferson';
$matches = array();
foreach($example as $k=>$v) {
if(preg_match("/\b$searchword\b/i", $v)) {
$matches[$k] = $v;
echo $matches[$k]."<br>";
}
}
The result will only "Emma Jefferson"
Then if i use this code
b.php
$filename = "a.txt";
$example = file($filename, FILE_IGNORE_NEW_LINES);
$searchword = 'Emma Jefferson';
$matches = array();
foreach($example as $k=>$v) {
$searchword2 = str_ireplace(" ", "|", $searchword);
if(preg_match("/\b$searchword2\b/i", $v)) {
$matches[$k] = $v;
echo $matches[$k]."<br>";
}
}
The result will be like this
Amy Jefferson
Emma West
Donna Jefferson
Emma Watson
Emma Jefferson
Unique result, but "Emma Jefferson" in the last result
So the question is how I can search Emma Jefferson, the result sort was like this
Emma Jefferson
Emma Watson
Emma West
Amy Jefferson
Donna Jefferson
So basically it search for "Emma Jefferson" entire word first, then "Emma" and the last one is "Jefferson"
UPDATE
I vote for Don't Panic code for this problem, but i wanna say thank you for all contributor here Don't Panic, RomanPerekhrest, Sui Dream, Jere, i-man, all of you are the best!!
Pattygeek
I don't know of a way to take the position of the matches into account with a regex solution, but if you convert the search string and the terms to arrays of words, it can be done.
With this approach, we iterate the text items and build an array of position matches for each word in the search term, then sort the result by number of matches, then position of matches.
$search_words = explode(' ', strtolower($searchword));
foreach ($example as $item) {
$item_words = explode(' ', strtolower($item));
// look for each word in the search term
foreach ($search_words as $i => $word) {
if (in_array($word, $item_words)) {
// add the index of the word in the search term to the result
// this way, words appearing earlier in the search term get higher priority
$result[$item][] = $i;
}
}
}
// this will sort alphabetically if the uasort callback returns 0 (equal)
ksort($result);
// sort by number of matches, then position of matches
uasort($result, function($a, $b) {
return count($b) - count($a) ?: $a <=> $b;
});
// convert keys to values
$result = array_keys($result);
Complex solution:
$lines = file('a.txt', FILE_IGNORE_NEW_LINES);
$name = 'Emma';
$surname = 'Jefferson';
$emmas = $jeffersons = [];
foreach ($lines as $l) {
if (strpos($l, $name) === 0) {
$emmas[] = $l;
} elseif ( strrpos($l, $surname) === (strlen($l) - strlen($surname)) ) {
$jeffersons[] = $l;
}
}
usort($emmas, function($a,$b){
return strcmp(explode(' ', $a)[1], explode(' ', $b)[1]);
});
usort($jeffersons, function($a,$b){
return strcmp($a, $b);
});
$result = array_merge($emmas, $jeffersons);
print_r($result);
The output:
Array
(
[0] => Emma Jefferson
[1] => Emma Watson
[2] => Emma West
[3] => Amy Jefferson
[4] => Donna Jefferson
)
You would have to write a new loop or start sorting your Array afterwords, because the foreach-loop takes one element name at the time, tests if it matches your search word and if it does, the name goes at the end of your new Array $matches[]. So the
if(preg_match("/\b$searchword2\b/i", $v)) {
$matches[$k] = $v;
echo $matches[$k]."<br>";
}
part does not know anything about the names that are or aren't already inside of $matches[].
So my suggestion would be:
$filename = "a.txt";
$example = file($filename, FILE_IGNORE_NEW_LINES);
$searchword = 'Emma Jefferson';
$matches = array();
$searchword2 = array($searchword, explode(" ", $searchword)[0], explode(" ", $searchword)[1]);
$isThisNameAlreadyInTheList;
foreach($searchword2 as $actualSearchword) {
foreach($example as $k=>$v) {
$isThisNameAlreadyInTheList = false;
foreach($matches as $match) {
if(preg_match("/\b$match\b/i", $v)) {
$isThisNameAlreadyInTheList = true;
}
}
if (!$isThisNameAlreadyInTheList) {
if(preg_match("/\b$actualSearchword\b/i", $v)) {
$matches[$k] = $v;
echo $matches[$k]."<br>";
}
}
}
}
I would use a preg_match_all solution like so:
$searchName = "Emma Jefferson";
$searchTerms = explode(' ', $searchName);
$pattern = "/(\b$searchTerms[0]\b \b$searchTerms[1]\b)|(\b$searchTerms[0]\b \w+)|(\w* \b$searchTerms[1]\b)/i";
$output = [];
preg_match_all($pattern, implode(' | ', $example), $out);
foreach($out as $k => $o){
if($k == 0){
continue;
}
foreach($o as $item){
if(!empty($item)){
$output[] = $item;
}
}
}
print_r($output);
You could also bring the file in as a string and avoid the implode portion.
You currently echo results immediately, so they ordered as they are in text.
You can search full string and partial matches, and then concatenate results.
foreach($example as $k=>$v) {
if(preg_match("/\b$searchword\b/i", $v)) {
$fullMatches[] = $v;
}
if(preg_match("/\b$searchword2\b/i", $v)) {
$matches[] = $v;
}
}
$matches = array_unique(array_merge($fullMatches, $matches));
foreach($matches as $k => $v)
echo $v . "<br>";
Update:
Multiple words variant:
$words = ['Emma', 'Jefferson'];
$matches = array();
foreach($example as $k => $v) {
$fullStr = implode(' ', $words);
if(preg_match("/\b$fullStr\b/i", $v))
$matches[0][] = $v;
$str = "";
$i = 1;
foreach($words as $word) {
if ($str === "")
$str = $word;
else
$str .= '|' . $word;
if(preg_match("/\b$str\b/i", $v))
$matches[$i][] = $v;
$i++;
}
}
$result = array();
foreach($matches as $firstKey => $arr) {
foreach($arr as $secondKey => $v) {
$result[] = $v;
}
}
$result = array_unique($result);
foreach($result as $k => $v)
echo $v . "<br>";
I'm trying to replicate Facebook's nested request syntax in PHP, converting the fields parameter into a multidimensional array.
/me?fields=name,updated_time,photos{name,source},likes{name,link},events.limit(4){name,start_time,end_time,photos}
Would result in something along the lines of...
Array
(
[name]
[updated_time]
[photos] => Array
(
[name]
[source]
)
[likes] => Array
(
[name]
[link]
)
)
Figured out how to match the graph API Using a loop. Decided it would be best to keep the filter, and limit modifiers as part of the object in order to keep the array as clean as possible
$a = $input;
$output = array();
$outputStacktrace = array(&$output);
$depth = 0;
$buffer = $key = '';
$m = memory_get_usage();
for ($i = 0; $i < strlen($a); $i++)
if ($a[$i] == ',') {
if (strlen($buffer))
if($depth == 0){
if(is_array($outputStacktrace[0]) && empty($outputStacktrace[0])){
$outputStacktrace[$depth][$buffer] = array();
}
} else {
$outputStacktrace[$depth][$key ? $key : count($outputStacktrace[$depth])] = $buffer;
}
$buffer = $key = '';
} elseif ($a[$i] == '{') {
$outputStacktrace[$depth][$buffer] = array();
$outputStacktrace[$depth + 1] = &$outputStacktrace[$depth][$buffer];
$depth++;
$buffer = '';
} elseif ($a[$i] == '}') {
if (strlen($buffer))
$outputStacktrace[$depth][$key ? $key : count($outputStacktrace[$depth])] = $buffer;
$buffer = $key = '';
unset($outputStacktrace[$depth]);
$depth--;
} else {
$buffer .= $a[$i];
}
if( $buffer!='' )
$outputStacktrace[$depth][$key ? $key : count($outputStacktrace[$depth])] = $buffer;
return ($output);
I have some data in this format:
even--heaped<br />
even--trees<br />
hardrocks-cocked<br />
pebble-temple<br />
heaped-feast<br />
trees-feast<br />
and I want to end up with an output so that all lines with the same words get added to each other with no repeats.
even--heaped--trees--feast<br />
hardrocks--cocked<br />
pebbles-temple<br />
i tried a loop going through both arrays but its not the exact result I want. for an array $thing:
Array ( [0] => even--heaped [1] => even--trees [2] => hardrocks--cocked [3] => pebbles--temple [4] => heaped--feast [5] => trees--feast )
for ($i=0;$i<count($thing);$i++){
for ($j=$i+1;$j<count($thing);$j++){
$first = explode("--",$thing[$i]);
$second = explode("--",$thing[$j]);
$merge = array_merge($first,$second);
$unique = array_unique($merge);
if (count($unique)==3){
$fix = implode("--",$unique);
$out[$i] = $thing[$i]."--".$thing[$j];
}
}
}
print_r($out);
but the result is:
Array ( [0] => even--heaped--heaped--feast [1] => even--trees--trees--feast [4] => heaped--feast--trees--feast )
which is not what i want. Any suggestions (sorry about the terrible variable names).
This might help you:
$in = array(
"even--heaped",
"even--trees",
"hardrocks--cocked",
"pebbles--temple",
"heaped--feast",
"trees--feast"
);
$clusters = array();
foreach( $in as $item ) {
$words = explode("--", $item);
// check if there exists a word in an existing cluster...
$check = false;
foreach($clusters as $k => $cluster) {
foreach($words as $word) {
if( in_array($word, $cluster) ) {
// add the words to this cluster
$clusters[$k] = array_unique( array_merge($cluster, $words) );
$check = true;
break;
}
}
}
if( !$check ) {
// create a new cluster
$clusters[] = $words;
}
}
// merge back
$out = array();
foreach( $clusters as $cluster ) {
$out[] = implode("--", $cluster);
}
pr($out);
Try this code:
<?php
$data = array ("1--2", "3--1", "4--5", "2--6");
$n = count($data);
$elements = array();
for ($i = 0; $i < $n; ++$i)
{
$split = explode("--", $data[$i]);
$word_num = NULL;
foreach($split as $word_key => $word)
{
foreach($elements as $key => $element)
{
if(isset($element[$word]))
{
$word_num = $key;
unset($split[$word_key]);
}
}
}
if(is_null($word_num))
{
$elements[] = array();
$word_num = count($elements) - 1;
}
foreach($split as $word_key => $word)
{
$elements[$word_num][$word] = 1;
}
}
//combine $elements into words
foreach($elements as $key => $value)
{
$words = array_keys($value);
$elements[$key] = implode("--", $words);
}
var_dump($elements);
It uses $elements as an array of hashes to store the individual unique words as keys. Then combines the keys to create appropriate words.
Prints this:
array(2) {
[0]=>
string(10) "1--2--3--6"
[1]=>
string(4) "4--5"
}
Here is a solution with a simple control flow.
<?php
$things = array('even--heaped', 'even--trees', 'hardrocks--cocked',
'pebble--temple', 'heaped--feast' ,'trees--feast');
foreach($things as $thing) {
$str = explode('--', $thing);
$first = $str[0];
$second = $str[1];
$i = '0';
while(true) {
if(!isset($a[$i])) {
$a[$i] = array();
array_push($a[$i], $first);
array_push($a[$i], $second);
break;
} else if(in_array($first, $a[$i]) && !in_array($second, $a[$i])) {
array_push($a[$i], $second);
break;
} else if(!in_array($first, $a[$i]) && in_array($second, $a[$i])) {
array_push($a[$i], $first);
break;
} else if(in_array($first, $a[$i]) && in_array($second, $a[$i])) {
break;
}
$i++;
}
}
print_r($a);
?>
It seems you have already selected user4035's answer as best.
But i feel this one is optimized(Please correct me if i am wrong): eval.in
Code:
$array = Array ( 'even--heaped' , 'even--trees' ,'hardrocks--cocked' , 'pebbles--temple' , 'heaped--feast' , 'trees--feast' );
print "Input: ";
print_r($array);
for($j=0;$j < count($array);$j++){
$len = count($array);
for($i=$j+1;$i < $len;$i++){
$tmp_array = explode("--", $array[$i]);
$pos1 = strpos($array[$j], $tmp_array[0]);
$pos2 = strpos($array[$j], $tmp_array[1]);
if (!($pos1 === false) && $pos2 === false){
$array[$j] = $array[$j] . '--'.$tmp_array[1];unset($array[$i]);
}elseif(!($pos2 === false) && $pos1 === false){
$array[$j] = $array[$j] . '--'.$tmp_array[0];unset($array[$i]);
}elseif(!($pos2 === false) && !($pos1 === false)){
unset($array[$i]);
}
}
$array = array_values($array);
}
print "\nOutput: ";
print_r($array);
My ips.txt file contains the following content:
radie1230: 116.79.254.131
Y_O_L_O: 122.149.157.42
midgetman63: 121.121.14.101, 124.112.115.69, 114.182.51.1, 114.118.55.131, 111.21.22.156
kypero: 121.211.61.118, 117.117.117.46, 121.214.109.247, 111.219.37.75
lythorous: 111.161.225.214, 12.111.184.71, 1.112.201.113, 11.137.214.184, 1.115.21.117, 12.115.241.212, 11.117.116.217
This list contains usernames on the left, separated by : from IPs on the right. IPs are separated by ,.
What would be an implementation to create the following output?
Array (
[midgetman63] => Array
(
[0] => 121.121.14.101
[1] => 124.112.115.69
[2] => 114.182.51.1
[3] => 114.118.55.131
[4] => 111.21.22.156
)
)
Try this:
$dataFromFile = file('ips.txt');
$dataFromFile = array_map('trim', $dataFromFile);
$result = array();
foreach ($dataFromFile as $line) {
list($user, $ips) = explode(':', $line, 2);
$arrayOfIPs = explode(',', $ips);
$result[trim($user)] = array_map('trim', $arrayOfIPs);
}
var_dump($result);
if you dont have spaces at the end of the textfile, this should be work.
good luck.
$text = file_get_contents("ipsontext.txt");
$array = explode("\n",$text);
$finally_array = array();
foreach ($array as $key => $value) {
$this_key = explode(":",$value);
$this_values = explode(",",$this_key[1]);
foreach($this_values as $tv) {
$finally_array[$this_key[0]][] = $tv;
}
}
var_dump($finally_array);
Maybe this?
<?php
$output = array();
$search = 'something';
$lines = file('file.txt');
foreach($lines as $line) {
if(strpos($line, $search) !== false) {
$d = explode(':', $line);
$s = explode(',', $d[1]);
foreach $s as $i { array_push($output, $i); }
}
}
print_r($output);
?>
I need to parse an HTML document and to find all occurrences of string asdf in it.
I currently have the HTML loaded into a string variable. I would just like the character position so I can loop through the list to return some data after the string.
The strpos function only returns the first occurrence. How about returning all of them?
Without using regex, something like this should work for returning the string positions:
$html = "dddasdfdddasdffff";
$needle = "asdf";
$lastPos = 0;
$positions = array();
while (($lastPos = strpos($html, $needle, $lastPos))!== false) {
$positions[] = $lastPos;
$lastPos = $lastPos + strlen($needle);
}
// Displays 3 and 10
foreach ($positions as $value) {
echo $value ."<br />";
}
You can call the strpos function repeatedly until a match is not found. You must specify the offset parameter.
Note: in the following example, the search continues from the next character instead of from the end of previous match. According to this function, aaaa contains three occurrences of the substring aa, not two.
function strpos_all($haystack, $needle) {
$offset = 0;
$allpos = array();
while (($pos = strpos($haystack, $needle, $offset)) !== FALSE) {
$offset = $pos + 1;
$allpos[] = $pos;
}
return $allpos;
}
print_r(strpos_all("aaa bbb aaa bbb aaa bbb", "aa"));
Output:
Array
(
[0] => 0
[1] => 1
[2] => 8
[3] => 9
[4] => 16
[5] => 17
)
Its better to use substr_count . Check out on php.net
function getocurence($chaine,$rechercher)
{
$lastPos = 0;
$positions = array();
while (($lastPos = strpos($chaine, $rechercher, $lastPos))!== false)
{
$positions[] = $lastPos;
$lastPos = $lastPos + strlen($rechercher);
}
return $positions;
}
This can be done using strpos() function. The following code is implemented using for loop. This code is quite simple and pretty straight forward.
<?php
$str_test = "Hello World! welcome to php";
$count = 0;
$find = "o";
$positions = array();
for($i = 0; $i<strlen($str_test); $i++)
{
$pos = strpos($str_test, $find, $count);
if($pos == $count){
$positions[] = $pos;
}
$count++;
}
foreach ($positions as $value) {
echo '<br/>' . $value . "<br />";
}
?>
Use preg_match_all to find all occurrences.
preg_match_all('/(\$[a-z]+)/i', $str, $matches);
For further reference check this link.
Salman A has a good answer, but remember to make your code multibyte-safe. To get correct positions with UTF-8, use mb_strpos instead of strpos:
function strpos_all($haystack, $needle) {
$offset = 0;
$allpos = array();
while (($pos = mb_strpos($haystack, $needle, $offset)) !== FALSE) {
$offset = $pos + 1;
$allpos[] = $pos;
}
return $allpos;
}
print_r(strpos_all("aaa bbb aaa bbb aaa bbb", "aa"));
Another solution is to use explode():
public static function allSubStrPos($str, $del)
{
$searchArray = explode($del, $str);
unset($searchArray[count($searchArray) - 1]);
$positionsArray = [];
$index = 0;
foreach ($searchArray as $i => $s) {
array_push($positionsArray, strlen($s) + $index);
$index += strlen($s) + strlen($del);
}
return $positionsArray;
}
Simple strpos_all() function.
function strpos_all($haystack, $needle_regex)
{
preg_match_all('/' . $needle_regex . '/', $haystack, $matches, PREG_OFFSET_CAPTURE);
return array_map(function ($v) {
return $v[1];
}, $matches[0]);
}
Usage:
Simple string as needle.
$html = "dddasdfdddasdffff";
$needle = "asdf";
$all_positions = strpos_all($html, $needle);
var_dump($all_positions);
Output:
array(2) {
[0]=>
int(3)
[1]=>
int(10)
}
Or with regex as needle.
$html = "dddasdfdddasdffff";
$needle = "[d]{3}";
$all_positions = strpos_all($html, $needle);
var_dump($all_positions);
Output:
array(2) {
[0]=>
int(0)
[1]=>
int(7)
}
<?php
$mainString = "dddjmnpfdddjmnpffff";
$needle = "jmnp";
$lastPos = 0;
$positions = array();
while (($lastPos = strpos($html, $needle, $lastPos))!== false) {
$positions[] = $lastPos;
$lastPos = $lastPos + strlen($needle);
}
// Displays 3 and 10
foreach ($positions as $value) {
echo $value ."<br />";
}
?>