This appears to be a simple task, but none of the previous posts quite addresses the nuances of this particular problem. I appreciate your patience with a new programmer.
I want to divide a text file (comments.txt) into arrays with the tilde as a divider. Then I want to pass a user string variable (nam) to the PHP and search for this string. The result should echo every whole array that contains the string anywhere inside of it.
For example:
Array
(
[0] => hotdog
[1] => milk
[2] => dog catcher
)
A search for "dog" would produce on screen:
hotdog dog catcher
<?php
$search = $_POST['nam'];
$file = file_get_contents('comments.txt');
$split = explode("~", $file);
foreach ($split as $subarray)
{
if(in_array($search, $subarray))
{
echo $subarray;
}
}
?>
The simple task is now this embarrassing mess. If you are patient enough, could someone demonstrate the above code correctly? Thanks for your attention.
Assuming you have 'comments.txt' and it contains something like:
hamburger~hotdog~milk~dog catcher~cat~dogbone
then this should work
$comments = file_get_contents("comments.txt");
$array = explode("~",$comments);
$search = "dog";
$matches = array();
foreach($array as $item){ // check each comment in array
if(strstr($item, $search)){ // use strstr to check if $search is in $item
$matches[] = $item; // if it is, add it to the array $matches
}
}
var_dump($matches);
First, you might want to try using file() instead of file_get_contents(). This should do what you're looking for:
<?php
$search = $_POST['nam'];
$file = file('contents.txt');
$matches = array();
foreach ($file as $k => $v) {
if ($a = explode('~', $v)) {
foreach ($a as $possible_match) {
if (preg_match('"/'. $search .'"/i', $possible_match)) {
$matches[] = $possible_match;
}
}
}
print_r($matches);
?>
This method will allow you to maintain several different records (one in each line of the file) and interpret/process them independently.
Related
I have strings in following format:
$strings[1] = cat:others;id:4,9,13
$strings[2] = id:4,9,13;cat:electric-products
$strings[3] = id:4,9,13;cat:foods;
$strings[4] = cat:drinks,foods;
where cat means category and id is identity number of a product.
I want to split these strings and convert into arrays $cats = array('others'); and $ids = array('4','9','13');
I know that it can be done by foreach and explode function through multiple steps. I think I am somewhere near, but the following code does not work.
Also, I wonder if it can be done by preg_match or preg_split in fewer steps. Or any other simpler method.
foreach ($strings as $key=>$string) {
$temps = explode(';', $string);
foreach($temps as $temp) {
$tempnest = explode(':', $temp);
$array[$tempnest[0]] .= explode(',', $tempnest[1]);
}
}
My desired result should be:
$cats = ['others', 'electric-products', 'foods', 'drinks';
and
$ids = ['4','9','13'];
One option could be doing a string compare for the first item after explode for cat and id to set the values to the right array.
$strings = ["cat:others;id:4,9,13", "id:4,9,13;cat:electric-products", "id:4,9,13;cat:foods", "cat:drinks,foods"];
foreach ($strings as $key=>$string) {
$temps = explode(';', $string);
$cats = [];
$ids = [];
foreach ($temps as $temp) {
$tempnest = explode(':', $temp);
if ($tempnest[0] === "cat") {
$cats = explode(',', $tempnest[1]);
}
if ($tempnest[0] === "id") {
$ids = explode(',', $tempnest[1]);
}
}
print_r($cats);
print_r($ids);
}
Php demo
Output for the first item would for example look like
Array
(
[0] => others
)
Array
(
[0] => 4
[1] => 9
[2] => 13
)
If you want to aggregate all the values in 2 arrays, you can array_merge the results, and at the end get the unique values using array_unique.
$strings = ["cat:others;id:4,9,13", "id:4,9,13;cat:electric-products", "id:4,9,13;cat:foods", "cat:drinks,foods"];
$cats = [];
$ids = [];
foreach ($strings as $key=>$string) {
$temps = explode(';', $string);
foreach ($temps as $temp) {
$tempnest = explode(':', $temp);
if ($tempnest[0] === "cat") {
$cats = array_merge(explode(',', $tempnest[1]), $cats);
}
if ($tempnest[0] === "id") {
$ids = array_merge(explode(',', $tempnest[1]), $ids);
}
}
}
print_r(array_unique($cats));
print_r(array_unique($ids));
Output
Array
(
[0] => drinks
[1] => foods
[3] => electric-products
[4] => others
)
Array
(
[0] => 4
[1] => 9
[2] => 13
)
Php demo
I don't generally recommend using variable variables, but you are looking for a sleek snippet which uses regex to avoid multiple explode() calls.
Here is a script that will use no explode() calls and no nested foreach() loops.
You can see how the \G ("continue" metacharacter) allows continuous matches relative the "bucket" label (id or cat) by calling var_export($matches);.
If this were my own code, I'd probably not create separate variables, but a single array containing id and cat --- this would alleviate the need for variable variables.
By using the encountered value as the key for the element to be added to the bucket, you are assured to have no duplicate values in any bucket -- just call array_values() if you want to re-index the bucket elements.
Code: (Demo) (Regex101)
$count = preg_match_all(
'/(?:^|;)(id|cat):|\G(?!^),?([^,;]+)/',
implode(';', $strings),
$matches,
PREG_UNMATCHED_AS_NULL
);
$cat = [];
$id = [];
for ($i = 0; $i < $count; ++$i) {
if ($matches[1][$i] !== null) {
$arrayName = $matches[1][$i];
} else {
${$arrayName}[$matches[2][$i]] = $matches[2][$i];
}
}
var_export(array_values($id));
echo "\n---\n";
var_export(array_values($cat));
All that said, I probably wouldn't rely on regex because it isn't very readable to the novice regex developer. The required logic is much simpler and easier to maintain with nested loops and explosions. Here is my adjustment of your code.
Code: (Demo)
$result = ['id' => [], 'cat' => []];
foreach ($strings as $string) {
foreach (explode(';', $string) as $segment) {
[$key, $values] = explode(':', $segment, 2);
array_push($result[$key], ...explode(',', $values));
}
}
var_export(array_unique($result['id']));
echo "\n---\n";
var_export(array_unique($result['cat']));
P.s. your posted coding attempt was using a combined operator .= (assignment & concatenation) instead of the more appropriate combined operator += (assignment & array union).
Excuse me if this question was already solved. I've searched trough the site and couldn't find an answer.
I'm trying to build a bi-dimensional array from a string. The string has this structure:
$workers="name1:age1/name2:age2/name3:age3"
The idea is to explode the array into "persons" using "/" as separator, and then using ":" to explode each "person" into an array that would contain "name" and "age".
I know the basics about the explode function:
$array=explode("separator","$string");
But I have no idea how to face this to make it bidimensional. Any help would be appreciated.
Something like the following should work. The goal is to first split the data into smaller chunks, and then step through each chunk and further subdivide it as needed.
$row = 0;
foreach (explode("/", $workers) as $substring) {
$col = 0;
foreach (explode(":", $substring) as $value) {
$array[$row][$col] = $value;
$col++;
}
$row++;
}
$array = array();
$workers = explode('/', "name1:age1/name2:age2/name3:age3");
foreach ($workers as $worker) {
$worker = explode(':', $worker);
$array[$worker[0]] = $worker[1];
}
Try this code:
<?php
$new_arr=array();
$workers="name1:age1/name2:age2/name3:age3";
$arr=explode('/',$workers);
foreach($arr as $value){
$new_arr[]=explode(':',$value);
}
?>
The quick solution is
$results = [];
$data = explode("/", $workers);
foreach ($data as $row) {
$line = explode(":", $row);
$results[] = [$line[0], $line[1]];
}
You could also use array_walk with a custom function which does the second level split for you.
This is another approach, not multidimensional:
parse_str(str_replace(array(':','/'), array('=','&'), $workers), $array);
print_r($array);
Shorter in PHP >= 5.4.0:
parse_str(str_replace([':','/'], ['=','&'], $workers), $array);
print_r($array);
yet another approach, since you didn't really give an example of what you mean by "bidimensional" ...
$workers="name1:age1/name2:age2/name3:age3";
parse_str(rtrim(preg_replace('~name(\d+):([^/]+)/?~','name[$1]=$2&',$workers),'&'),$names);
output:
Array
(
[name] => Array
(
[1] => age1
[2] => age2
[3] => age3
)
)
I have various values in a PHP array, that look like below:
$values = array("news_24", "news_81", "blog_56", "member_55", "news_27");
The first part before the underscore (news, blog, member) is dynamic so I would like to get all the matches in a specific section (news) followed by the numbers.
Something like below:
$section = "news";
$matches = preg_match('$section/[_])GETNUMBER/', $values);
This would return 24 and 27, but only where news was before the underscore.
Thanks.
$values = array("news_24", "news_81", "blog_56", "member_55", "news_27");
$section = "news";
foreach($values as $value) {
$matches = preg_match("/{$section}_(\\d+)/", $value, $number);
if ($matches)
echo $number[1], PHP_EOL;
}
$values = array("news_24", "news_81", "blog_56", "member_55", "news_27");
function func($type){
$results = null;
foreach($values as $val){
$curr = explode('_',$val);
if($curr[0]==$type){
$results[] = $curr[1];
}
}
return $results;
}
$News = func('news');
Good luck! :P
Note I added two cases:
$values = array ("news_24", "news_81", "blog_56", "member_55", "news_27",
"blognews_99", "news_2012_12");
$section = "news";
preg_match_all("/^{$section}_(\\d+)\$/m", implode("\n", $values), $matches);
print_r($matches[1]);
The implode might not be super efficient, but it's less code.
The difference is in the matching & regex.
This solution only outputs
Array
(
[0] => 24
[1] => 81
[2] => 27
)
While the others also output 2012 and the solution of Mark also 99.
Sorry for English is not my mother language, maybe the question title is not quite good. I want to do something like this.
$str = array("Lincoln Crown","Crown Court","go holiday","house fire","John Hinton","Hinton Jailed");
here is an array, "Lincoln Crown" contain "Lincoln" and "Crown", so remove next words, which contains these 2 words, and "Crown Court(contain Crown)" has been removed.
in another case. "John Hinton" contain "John" and "Hinton", so "Hinton Jailed(contain Hinton)" has been removed. the final output should be like this:
$output = array("Lincoln Crown","go holiday","house fire","John Hinton");
for my php skill is not good, it is not simply to use array_unique() array_diff(), so open a question for help, thanks.
I think this might work :P
function cool_function($strs){
// Black list
$toExclude = array();
foreach($strs as $s){
// If it's not on blacklist, then search for it
if(!in_array($s, $toExclude)){
// Explode into blocks
foreach(explode(" ",$s) as $block){
// Search the block on array
$found = preg_grep("/" . preg_quote($block) . "/", $strs);
foreach($found as $k => $f){
if($f != $s){
// Place each found item that's different from current item into blacklist
$toExclude[$k] = $f;
}
}
}
}
}
// Unset all keys that was found
foreach($toExclude as $k => $v){
unset($strs[$k]);
}
// Return the result
return $strs;
}
$strs = array("Lincoln Crown","Crown Court","go holiday","house fire","John Hinton","Hinton Jailed");
print_r(cool_function($strs));
Dump:
Array
(
[0] => Lincoln Crown
[2] => go holiday
[3] => house fire
[4] => John Hinton
)
Seems like you would need a loop and then build a list of words in the array.
Like:
<?
// Store existing array's words; elements will compare their words to this array
// if an element's words are already in this array, the element is deleted
// else the element has its words added to this array
$arrayWords = array();
// Loop through your existing array of elements
foreach ($existingArray as $key => $phrase) {
// Get element's individual words
$words = explode(" ", $phrase);
// Assume the element will not be deleted
$keepWords = true;
// Loop through the element's words
foreach ($words as $word) {
// If one of the words is already in arrayWords (another element uses the word)
if (in_array($word, $arrayWords)) {
// Delete the element
unset($existingArray[$key]);
// Indicate we are not keeping any of the element's words
$keepWords = false;
// Stop the foreach loop
break;
}
}
// Only add the element's words to arrayWords if the entire element stays
if ($keepWords) {
$arrayWords = array_merge($arrayWords, $words);
}
}
?>
As I would do in your case:
$words = array();
foreach($str as $key =>$entry)
{
$entryWords = explode(' ', $entry);
$isDuplicated = false;
foreach($entryWords as $word)
if(in_array($word, $words))
$isDuplicated = true;
if(!$isDuplicated)
$words = array_merge($words, $entryWords);
else
unset($str[$key]);
}
var_dump($str);
Output:
array (size=4)
0 => string 'Lincoln Crown' (length=13)
2 => string 'go holiday' (length=10)
3 => string 'house fire' (length=10)
4 => string 'John Hinton' (length=11)
I can imagine quite a few techniques that can provide your desired output, but the logic that you require is poorly defined in your question. I am assuming that whole word matching is required -- so word boundaries should be used in any regex patterns. Case sensitivity isn't mentioned. I am unsure if only fully unique elements (multi-word strings) should have their words entered into the black list. I'll offer a few snippets, but choosing the appropriate technique will depend on exact logical requirements.
Demo
$output = [];
$blacklist = [];
foreach ($input as $string) {
if (!$blacklist || !preg_match('/\b(?:' . implode('|', $blacklist) . ')\b/', $string)) {
$output[] = $string;
}
foreach(explode(' ', $string) as $word) {
$blacklist[$word] = preg_quote($word);
}
}
var_export($output);
Demo
$output = [];
$blacklist = [];
foreach ($input as $string) {
$words = explode(' ', $string);
foreach ($words as $word) {
if (in_array($word, $blacklist)) {
continue 2;
}
}
array_push($blacklist, ...$words);
$output[] = $string;
}
var_export($output);
And my favorite because it performs fewest iterations in the parent loop, is more compact, and doesn't require the declaration/maintenance of a blacklist array.
Demo
$output = [];
while ($input) {
$output[] = $words = array_shift($input);
$input = preg_grep('~\b(?:\Q' . str_replace(' ', '\E|\Q', $words) . '\E)\b~', $input, PREG_GREP_INVERT);
}
var_export($output);
You can explode each string in the original array and then compare per-words using a loop (comparing each word from one array with each word from another, and if they match, remove the whole array).
array_unique() example
<?php
$input = array("a" => "green", "red", "b" => "green", "blue", "red");
$result = array_unique($input);
print_r($result);
?>
output:
Array
(
[a] => green
[0] => red
[1] => blue
)
Source
I want to select specific words from a sentence according to my array list
$sentence = "please take this words only to display in my browser";
$list = array ("display","browser","words","in");
I want the output just like " words display in browser"
please somebody help me with this one. THX
I wonder if this one liner would do it :
echo join(" ", array_intersect($list, explode(" ",$sentence)));
Use at your own risk :)
edit : yay, it does the job, just tested
You can do it with preg_match:
$sentence = "please take this words only to display in my browser";
$list = array ("display","browser","words","in");
preg_match_all('/\b'.implode('\b|\b', $list).'\b/i', $sentence, $matches) ;
print_r($matches);
You'll get the words in order
Array
(
[0] => Array
(
[0] => words
[1] => display
[2] => in
[3] => browser
)
)
But be careful with regular expressions performance if the text is not that simple.
I don't know any short version for this rather than checking word by word.
$words = explode(" ", $sentence);
$new_sentence_array = array();
foreach($words as $word) {
if(in_array($word, $list)) {
$new_sentence_array[] = $word;
}
}
$new_sentece = implode(" ", $new_sentence_array);
echo $new_sentence;
I think you could search the string for each value in the array and assign it to a new array with the strpos value as the key; that would give you a sortable array that you could then output in the order that the terms appear in the string. See below, or example.
<?php
$sentence = "please take this words only to display in my browser";
$list = array ("display","browser","words","in");
$found = array();
foreach($list as $k => $v){
$position = strpos(strtolower($sentence), strtolower($v));
if($position){
$found[$position] = $v;
}
}
ksort($found);
foreach($found as $v){
echo $v.' ';
}
?>
$narray=array();
foreach ($list as $value) {
$status=stristr($sentence, $value);
if ($status) {
$narray[]=$value;
}
}
echo #implode(" ",$narray);