Add text to specific line without removing the exist line in php - php

I'm trying to add only last name if first name is same
data.txt
Alice Sandy
Alice Nanami
James Watt
Alice Monica
Johann Gauss
to result.txt
Alice Sandy Nanami Monica
James Watt
Johann Gauss
I try with this code
$resultFile = "result.txt";
$search = "Alice";
$lineNumber = false;
if ($handle = fopen($result, "r")) {
$count = 0;
while (($line = fgets($handle, 4096)) !== FALSE and !$lineNumber) {
$count++;
$lineNumber = (strpos($line, $search) !== FALSE) ? $count : $lineNumber;
$isExist = (strpos($line, $search) !== FALSE) ? "yup" : "no";
}
fclose($handle);
}
if($isExist=="yup"){
$lines = file($resultFile);
$lines[$lineNumber] = $lines[$lineNumber].' '.$lastName;
file_put_contents($result, implode('', $lines));
}else{
$fullName = $firstName.' '.$lastName;
$fileOpen = fopen($result, "a");
fwrite($fileOpen,$fullName);
fclose($fileOpen);
$addBreaker = "\n";
$splResult = new SplFileObject($resultFile, 'a');
$splResult->fwrite($addBreaker);
}
But it give error offset (I'm using PHP 7) and the result is untidy
Alice Sandy Nanami
Monica
James Watt
Johan Gauss
Thanks for help

Another apporach instead of replacing lines would be save every line to an array and then iterate over array and save to the new file. You can also use the same file as an $outputFile.
$inputFile = 'names.txt';
$outputFile = 'result.txt';
$names = [];
if ($handle = fopen($inputFile, "r")) {
$count = 0;
while (($line = fgets($handle, 4096)) !== FALSE) {
$count++;
$lineNames = explode(' ', $line);
$names[$lineNames[0]][] = trim($lineNames[1]);
}
fclose($handle);
}
$handle = fopen($outputFile, 'w');
foreach ($names as $firstName => $lastNames) {
fwrite($handle, $firstName . ' ' . implode(' ', $lastNames) . PHP_EOL);
}
Two additional notes:
Don't use string as boolean value.
$isExist = (strpos($line, $search) !== FALSE) ? "yup" : "no";
Use just following condition. It's enough
$isExist = (strpos($line, $search) !== FALSE)
If you read lines from file you copy also new lines char, although you can't see them quite well in the output. You should trim all whitespace characters before inserting/replacing etc. to avoid old structure of file.

Use file() to collect the file contents as an array of lines. My snippet starts from there with $lines.
Iterate the array and makes each line modifiable by reference. (&)
Locate the first occurring needle match that not only exists in the line but matches the whole first word so that you don't get false-positive matching.
Then declare the first match as a reference variable (=&) and continue iterating the array. Any subsequent matches will have the delimiting space and second word appended to the reference variable. Then immediate unset the line to be purged from the document.
When done, re-implode the data and stuff the content into the result file.
This is clean, readable, and only needs one loop.
Code: (Demo)
// $lines = file('result.txt', FILE_IGNORE_NEW_LINES);
$lines = [
'Alice Sandy',
'Alice Nanami',
'James Watt',
'Alice Monica',
'Johann Gauss',
'Cooper Alice',
];
$needle = 'Alice';
foreach($lines as $index => &$line) {
if ($needle === strstr($line, ' ', true)) { // check whole first word
if (!isset($firstOccurrence)) {
$firstOccurrence =& $line;
} else {
$firstOccurrence .= strstr($line, ' ');
unset($lines[$index]);
}
}
}
var_export($lines);
// file_put_contents('result.txt', implode(PHP_EOL, $lines));
Output:
array (
0 => 'Alice Sandy Nanami Monica',
2 => 'James Watt',
4 => 'Johann Gauss',
5 => 'Cooper Alice',
)
P.s if you want to know if any rows were changed you could check if the original array is === the new array after looping, or you could just use a boolean flag variable in the else condition.

Related

How to remove duplicates from a PHP string separated by "X"?

I have a csv file that looks like this:
13:BOOT2700 X;27
13:BOOT2700 X;27
13:BOOT2700 X;27
13:BOOT2700 X;27
13:BOXER1136 X;11.36
13:BOXER1364 X;13.64
13:BOXER1591 X;15.91
13:BOXER909 X;9.09
...
I would like to remove the duplicates of data[0] and remove the spaces and the "X" at the end of the string. For the second part it works correctly but I can't delete the duplicates. I tried this code but they remain. It shows me each time the first values while they are identical.
In the end I would like this:
13:BOOT2700;27
13:BOXER1136;11.36
13:BOXER1364;13.64
13:BOXER1591;15.91
13:BOXER909;9.09
How can I do it?
Thanks for your help
<?php
$file = "BI6_20211214_0905_15000.txt";
if (($handle = fopen($file, "r")) !== false) {
while (($data = fgetcsv($handle, 9000000, ";")) !== false) {
$uniqueStr = implode('X', array_unique(explode('X', $data[0]))); //doesn't work
$clean_name = str_replace(' ', '', $data[0]);
$clean_name2 = str_replace('X', '', $clean_name);
echo $clean_name2; //13:BOOT2700
echo ("<br>");
}
}
fclose($handle);
echo "good !";
?>
Here's the entire code simplified and with comments that can help OP and others understand how you can process that.
I have 2 files:
input.txt
13:BOOT2700 X;27
13:BOOT2700 X;28
13:BOOT2700 X;29
13:BOOT2700 X;29
13:BOXER1136 X;11.36
13:BOXER1364 X;13.64
13:BOXER1591 X;15.91
13:BOXER909 X;9.09
When you run the code below, its result will be
===> Processing input.txt
Result:
13:BOOT2700;27
13:BOXER1136;11.36
13:BOXER1364;13.64
13:BOXER1591;15.91
13:BOXER909;9.09
input2.txt
13:BOOT111 X;27
13:BOOT2700 X;29
13:BOOT2700 X;29
13:BOXER1136 X;11.36
13:BOXER1364 X;13.64
13:BOXER1591 X;15.91
13:BOXER909 X;9.09
Its output will be
===> Processing input2.txt
Result:
13:BOOT111;27
13:BOOT2700;29
13:BOXER1136;11.36
13:BOXER1364;13.64
13:BOXER1591;15.91
13:BOXER909;9.09
Code
<?php
# Remove byte order mark (BOM)
function remove_utf8_bom($text) {
$bom = pack('H*','EFBBBF');
$text = preg_replace("/^$bom/", '', $text);
return $text;
}
# get list of all files
$dir = 'your-path/';
$allFiles = scandir($dir);
# process each file
foreach($allFiles as $file) {
if (in_array($file, array(".",".."))) {
continue;
}
if (strpos($file, 'BI6_') === false) {
continue;
}
echo "===> Processing $file\n";
$file = $dir.$file;
$filename = basename( $file );
# stores unique items like 13:BOOT2700, 13:BOXER1136 etc.
$processedItems = array();
# stores lines in the format we need
$finalResult = array();
$handle = fopen($file, 'r');
if ($handle === false) {
echo "Problem opening $file. Skipping.\n";
continue;
}
# read each line
while(!feof($handle)) {
$line = fgets($handle);
$line = remove_utf8_bom($line);
# skip empty lines
if (strlen(trim($line)) === 0) {
continue;
}
# split by X;, trim the first part
$lineSplit = explode('X;', $line);
$lineSplit[0] = trim($lineSplit[0]);
# check if the first part (such as 13:BOOT2700) is processed already
# if so, don't do anything else
if (in_array($lineSplit[0], $processedItems) === true) {
continue;
}
else {
# store the first part in processed items and create the newly
# formatted line; store that in final result
$processedItems[] = $lineSplit[0];
$finalResult[] = $lineSplit[0] . ';' . $lineSplit[1];
}
}
fclose($handle);
# show the final result
echo "Result:\n";
foreach ($finalResult as $x) {
echo $x;
}
}
echo "Done";
?>
The file is read into an array with file. With array_map and preg_replace the spaces and the X are removed from each line. array_unique then removes the duplicate entries.
$array = file('input.txt',FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$array = array_map(function($v){return preg_replace('/ +X;/',';',$v);}, $array);
$array = array_unique($array);
The result is an array.
array (
0 => "13:BOOT2700;27",
4 => "13:BOXER1136;11.36",
5 => "13:BOXER1364;13.64",
6 => "13:BOXER1591;15.91",
7 => "13:BOXER909;9.09",
)
If a file is required as a result, the array can be converted into a string with implode and written to a file with file_put_contents.
$str = implode("\r\n",$array);
file_put_contents('input.csv', $str);

How to read specific lines from a text file in PHP

I have a txt file which has a lot of lines and the values in every line are separated with commas.
I want to read the 1st line alone which I did already using fgets :
$head = fgets(fopen($file, 'r'));
$headValues = explode(',', $head);
but now I want to read every other line from line 2 until the end of file and put those values into an array.
I searched for similar solutions but couldn't find any
Just use descriptor
$fd = fopen($file, 'r');
$head = fgets($fd);
$headValues = explode(',', $head);
$data = [];
while(($str = fgets($fd)) !== false) {
$otherValues = explode(',', $str);
$data[] = $otherValues;
}
This uses fgetcsv for the lines you care about and uses array_combine to put the headers and the line data together.
$fh = fopen($file, 'r');
$headValues = fgetcsv($fh);
$data = [];
while (true) {
if ( ($values = fgetcsv($fh)) === false ) {
break;
}
$data[] = array_combine($headValues, $values);
if ( fgets($fh) === false ) {
break;
}
}
fclose($fh);
print_r($data);
It checks at each read in case the EOF has been reached and then breaks out of the read loop.
You could use file(), array_map() and array_shift() :
$lines = file($file) ; // get file as array.
$lines = array_map(function($l){ return explode(',', $l); }, $lines);
$headValues = array_shift($lines); // get first values (removed from $lines)
So, $lines will contains all lines except the first one.

PHP class value not accessible after initializing

I am trying to turn an input file in the form below into a series of objects that can be manipulated.
arabian_sea_area = {
1926 1927 1931 1932 1933 2029 2030
}
gulf_of_aden_sea_area = {
1925 2024 5285 5286
}
sdf
<?php
$all_areas = array();
if (($handle = fopen("area.txt", "r")) == False)
{
die("failed to open file\n");
}
while (($line = fgets($handle)) !== FALSE)
{
if (ctype_alpha($line[0]))
{
$line= explode(" ",$line);
// echo($line[0]."\n");
$area = $line[0];
$IDs = explode(" ", fgets($handle));
$IDs[0] = ltrim($IDs[0], ' '); // trying to remove tab from first ID
$all_areas[$area] = $IDs;
//array_push($all_areas, $temp);
}
}
//echo("a\n");
print_r($all_areas["arabian_sea_area"]);
//var_dump ($all_areas);
?>
The values print correctly in the commented out debug lines but fail to print anything for the var_dump at the end.
edit: I realize this was unclear, what I was trying to do was create a master "all_areas" array that linked to objects titled the first line (ie. arabian_sea_area etc.) and I could then get at the numerical Ids for each area algorithmically for a later script.
There are many issues with your code:
1-
if (ctype_alpha($line[0]))
{
$line= explode(" ",$line);
//echo($line[0]."\n");
$temp = $line[0];
$temp = new Area;
$temp->filler($line, $handle);
}
you are creating a $temp variable but you forgot to push it to your main array $all_areas. use array_push
2-
var_dump ($arabian_sea_area);
$arabian_sea_area does not exist.
Did you mean to print your main array $all_areas ?
3- Recommendation:
On errors (echo("failed to open file\n");) its recommended to use die("failed to open file\n"); instead of echo. as die will stop the rest of the script from executing.
-- UPDATE --
I edited your code in a way that should work fine:
class Area {
public $area_name;
public $IDs = array();
public function filler($line, $handle) {
$this->area_name = $line[0];
//echo($this->area_name."\n");
$this->IDs = explode(" ", fgets($handle));
//print_r($this->IDs);
}
}
$all_areas = array();
if (($handle = fopen("area.txt", "r")) == False)
{
die("failed to open file\n");
}
while (($line = fgets($handle)) !== FALSE)
{
if (ctype_alpha($line[0]))
{
$line= explode(" ",$line);
// echo($line[0]."\n");
$temp = $line[0];
$temp = new Area;
$temp->filler($line, $handle);
array_push($all_areas, $temp);
}
}
//echo("a\n");
var_dump ($all_areas);
You might wanna update it to remove / filter empty values.

How can I find a needle in a haystack, and show the entire line?

How can I find a needle in a haystack, and show the entire line?
log.txt :
Log #5731: JohnDoe has arrested JaneDoe
Log #5732: DonDoe has arrested JaneDoe
I want to search for "JohnDoe" and display the whole lineLog #5731: JohnDoe has arrested JaneDoe.
Also, if there's several logs for one person I want to show them all
You could explode your text by newline.
Then search for what you want using array_search method and have the key of that element in the array.
Tho I wouldn't recommend that first solution, if your log is or becomes big (which should be the case for most logs), since the entire log has to be loaded and put into an array. That eats up a massive ammount of resources.
I'd rather do like
<?php
$logfilepath = 'path/to/log.txt';
function searchLog($logfilepath, $searchQuery) {
$fileresource = fopen($logfilepath, 'r');
while (($buffer = fgets($handle)) !== false) {
//now search in buffer
if(strpos($buffer, $searchQuery) !== false) {
return $buffer;
}
}
}
Edit: If you want to find all occurences:
<?php
$logfilepath = 'path/to/log.txt';
function searchLog($logfilepath, $searchQuery) {
$fileresource = fopen($logfilepath, 'r');
$occurences = array();
while (($buffer = fgets($handle)) !== false) {
//now search in buffer
if(strpos($buffer, $searchQuery) !== false) {
$occurences[] = $buffer;
}
}
return $occurences;
}
If the data source is a file and the definition of "entire line" is a newline delimiter, I would use file() to explode the data into an array and then loop through it:
function findLines($file_path, $needle) {
$file_lines = file($file_path);
foreach($file_lines as $line) {
if(strpos($line, $needle) !== false) {
$matching_lines[] = $line;
}
}
return $matching_lines;
}
$needle = 'JohnDoe';
$log_entries = findLines('/path/to/log.txt', $needle);

Php get value from text file

I have this textfile:
foo: bar
el: macho
bing: bong
cake color: blue berry
mayo: ello
And I what I'm trying to accomplish is that if I "look" for foo, it returns bar (if I look for bing, it should return bong). A way a tried to accomplish this is first search though the file, return the line with the result, put it in a string and remove everything before the ":" and display the string.
// What to look for
$search = 'bing';
// Read from file
$lines = file('file.txt');
foreach($lines as $line)
{
// Check if the line contains the string we're looking for, and print if it does
if(strpos($line, $search) !== false)
echo $line;
$new_str = substr($line, ($pos = strpos($line, ',')) !== false ? $pos + 1 : 0);
}
echo "<br>";
echo "bing should return bong:";
echo $new_str;
But it doesn't work. Up here is just one of the many things I've tried.
Sources:
Many stackoverflow links on and comparable searches:
https://www.google.com/search?client=opera&q=php+remove+everything+after
https://www.google.com/search?client=opera&q=php+search+text+file+return+line
I've asked a question before, but the answers are to "professional" for me, I really need a noob-proof solution/answer. I've been trying to figure it out all day but I just can't get this to work.
Edit:
It's solved! Thank you so much for your time & help, I hope this might be useful to someone else to!
This should work with what you are looking for, I tested it on my server and it seems to fit what you are looking for.
$lines_array = file("file.txt");
$search_string = "bing";
foreach($lines_array as $line) {
if(strpos($line, $search_string) !== false) {
list(, $new_str) = explode(":", $line);
// If you don't want the space before the word bong, uncomment the following line.
//$new_str = trim($new_str);
}
}
echo $new_str;
?>
I would do it this way:
foreach($lines as $line)
{
// explode the line into an array
$values = explode(':',$line);
// trim the whitspace from the value
if(trim($values[1]) == $search)
{
echo "found value for ".$search.": ".$values[1];
// exit the foreach if we found the needle
break;
}
}
$search = 'bing';
// Read from file
$lines = file('text.txt');
$linea='';
foreach($lines as $line)
{
// Check if the line contains the string we're looking for, and print if it does
if(strpos($line, $search) !== false) {
$liner=explode(': ',$line);
$linea.= $liner[1];
}
}
echo 'Search returned: '. $linea;
Explanation: - $linea var is created before loop, and it will contain search result. If value is found on line - explode string, and make array, get second var from array, put it in search results container variable.
As your data is almost YAML [see lint], you could use a parser in order to get the associated PHP array.
But if can go with your solution as well:
// What to look for
$search = 'bing';
// Read from file
$lines = file('file.txt');
foreach($lines as $line)
{
// Check if the line contains the string we're looking for, and print if it does
if(strpos($line, $search) !== false){
echo array_pop(explode(":", $line));
}
}
Use fgetcsv:
$bits = array();
if (($handle = fopen('t.txt','r')) !== FALSE) {
while (($data = fgetcsv($handle, 0, ":")) !== FALSE) {
$bits[$data[0]] = $data[1];
}
}
# Now, you search
echo $bits['foo'];
$bits will have a key for each split part, which makes your ultimate goal quite simple. Here is what it looks like:
Array
(
[foo] => bar
[el] => macho
[bing] => bong
[cake color] => blue berry
[mayo] => ello
)

Categories