strpos result 0 stops while loop - php

i need to find the all positions of a particular character in a string. I am using the following code
$pos = 0;
$positions = array();
while( $pos = strpos($haystack,$needle,$pos){
$positions[] = $pos;
$pos = $pos+1;
}
the problem with this code is that when the needle is at location 1,its returns 1 and so doesn't enter the loop.
So i tried the following
$pos = 0;
$positions = array();
while( ($pos = strpos($haystack,$needle,$pos) || (strpos($haystack,$needle,$pos)=== 0){
$positions[] = $pos;
$pos = $pos+1;
}
and,
$pos = 0;
$positions = array();
while( ($pos = strpos($haystack,$needle,$pos) || (strpos($haystack,$needle,$pos) != false){
$positions[] = $pos;
$pos = $pos+1;
}
But nothing seems to be working. Is there any other way.
The two alternative i tried give me
Allowed memory size of 268435456 bytes exhausted
which i think has more to do with programming error than memory issue.
Plz help.

You need to use !== instead of != because zero is considered false so you need to compare by type as well:
while($pos = (strpos($haystack,$needle,$pos) !== false){
$positions[] = $pos;
$pos++;
}
Edit
See the working version of your code from the comment:
$positions = array();
while( ($pos = strpos('lowly','l',$pos)) !== false){
$positions[] = $pos;
$pos++;
}
print_r($positions);
See it working here.

Use this code..
$start = 0;
while ($pos = strpos($string, ',', $start) !== FALSE) {
$count++;
$start = $pos + 1;
}

Related

Issue with duplicate array values from preg_match_all

first time resorting to actually posting on SO.
Also sorry if this has been asked many times, i think ive about read most of them here, but still no dice.
I have a generated log file continaing text i wish to extract the line in the log file is this:
{22:30:47} System:"Obambivas" StarPos:(-59.938,7.375,56.813)ly Body:13 RelPos:(-0.529636,-0.130899,0.838064)km NormalFlight
So far ive manaaged to get the matches via preg_match_all, and works fine.
However i really need each System:"" only once as the log may have several exacly the same.
Ive tried to use array_unique, but im fairly sure im using it wrong as it either retruns nothing or the same results, ie 10+ matches for each match found
So i need just each unique match from the matches found in the log file.
My code so far (sorry if its messy)
And thanks in advance
if (is_dir($log) && is_readable($log)) {
if (!$files = scandir($log, SCANDIR_SORT_DESCENDING)) {
}
$newest_file = $files[0];
if (!$line = file($log . "/" . $newest_file)) {
} else {
foreach ($line as $line_num => $line) {
$pos = strpos($line, 'System:"');
$pos2 = strrpos($line, "ProvingGround");
if ($pos !== false && $pos2 === false) {
preg_match_all("/\System:\"(.*?)\"/", $line, $matches);
$cssystemname = $matches[1][0];
$curSys["name"] = $cssystemname;
preg_match_all("/\StarPos:\((.*?)\)/", $line, $matches2);
$curSys["coordinates"] = $matches2[1][0];
$coord_parts = explode(",", $curSys["coordinates"]);
$curSys["x"] = $coord_parts[0];
$curSys["y"] = $coord_parts[1];
$curSys["z"] = $coord_parts[2];
echo $curSys["name"].' | Coords: '.$curSys["x"].','.$curSys["y"].','.$curSys["z"].'<br />';
}
}
}
}
I added $hash array to avoid duplicates
if (is_dir($log) && is_readable($log)) {
if (!$files = scandir($log, SCANDIR_SORT_DESCENDING)) {
}
$newest_file = $files[0];
if (!$line = file($log . "/" . $newest_file)) {
} else {
$hash = array();
foreach ($line as $line_num => $line) {
$pos = strpos($line, 'System:"');
$pos2 = strrpos($line, "ProvingGround");
if ($pos !== false && $pos2 === false) {
preg_match_all("/\System:\"(.*?)\"/", $line, $matches);
$cssystemname = $matches[1][0];
if ($hash[$cssystemname] == "")
{
$curSys["name"] = $cssystemname;
preg_match_all("/\StarPos:\((.*?)\)/", $line, $matches2);
$curSys["coordinates"] = $matches2[1][0];
$coord_parts = explode(",", $curSys["coordinates"]);
$curSys["x"] = $coord_parts[0];
$curSys["y"] = $coord_parts[1];
$curSys["z"] = $coord_parts[2];
echo $curSys["name"].' | Coords: '.$curSys["x"].','.$curSys["y"].','.$curSys["z"].'<br />';
}
} else $hash[$cssystemname] = "inhash";
}
}

php how to get whole line after spicific character from text file?

I have text file
name,name1
willhaveishere1
name,name2
willhaveishere2
name,name3
willhaveishere3
i want read it and return like that
$nn = name1
$ss = willhaveishere1
with my code i get only name1
my code is
$file1 = "file.txt";
$file = file($file1);
$count = count($file);
if($count > 0) {
$i = 1;
foreach($file as $row) {
$n = strstr($row, 'name,');
$cc = array("name,");
$dd = array("");
$nn = str_replace($cc, $dd, $n);
echo $nn;
$i++; } }
This is probably what you need
if($count > 0) {
foreach($file as $row) {
$pos = strpos($row, ',');
if($pos !== false){
echo substr($row, $pos + 1);
$nn[] = substr($row, $pos + 1);
} else {
echo $row;
$ss[] = $row;
}
}
}
EDIT
Yes, just loop through, but make sure both $nn and $ss has same count, which is depending on your file.
Also Note: mysql_* functions has been deprecated, so please use mysqli or PDO instead
$count = count($nn);
for($i=0; $i < $count; $i++){
$sql = "INSERT INTO users(name, line) VALUES('$nn[$i]', '$ss[$i]')"; mysql_query($sql);
}
EDIT 2
try this example:
$file = array(
0 => 'name,name1',
1 => 'willhaveishere1',
2 => 'name,name2',
3 => 'willhaveishere2',
4 => 'name,name3',
5 => 'willhaveishere3'
);
$count = count($file);
if($count > 0) {
foreach($file as $row) {
$pos = strpos($row, ',');
if($pos !== false){
$nn[] = substr($row, $pos + 1);
} else {
$ss[] = $row;
}
}
}
echo '<pre>';
$count = count($nn);
for($i=0; $i < $count; $i++){
$sql = "INSERT INTO users(name, line) VALUES('$nn[$i]', '$ss[$i]');";
echo $sql.PHP_EOL;
}
You can try this straightforward method:
if($fh = fopen("file.txt","r")){
$nameBefore = false;
//loop through every line of your file
while (!feof($fh)){
$line = fgets($fh);
//check if the name was detected in previous line
if ($nameBefore !== false)
{
//you have the set of name and line, do what you want
echo $nameBefore . ': ' . $line . '<br />';
$nameBefore = false;
}
else
{
//see if the line is made of two coma separated segments and the first one is 'name'
//Remember the name for the next line
$parts = explode(',', $line);
if (count($parts) == 2 && $parts[0] == 'name')
$nameBefore = $parts[1];
}
}
fclose($fh);
}
One option is to use strpos to find the first occurrence of the character in the line, and if found remove everything from the line before that position. This way you are left with only the part of the line you are interested in.
Code:
$character = ',';
$fileHandle = fopen('file.txt', 'r');
while (!feof($fileHandle)) {
// Retrieve the line from the file
$line = fgets($fileHandle);
// If the line contains the character
// Remove everything before the character
$charPos = strpos($line, $character);
if ($charPos !== false) {
$line = substr($line, $charPos + 1);
}
// Do something with the remainder of the line
echo $line . PHP_EOL;
}
fclose($fileHandle);
Output:
name1
willhaveishere1
name2
willhaveishere2
name3
willhaveishere3
If you wish to retrieve the following line, simply do another retrieve line call in your loop:
while (!feof($fileHandle)) {
// Retrieve two lines in one loop iteration
$lineOne = fgets($fileHandle);
$lineTwo = fgets($fileHandle);
}
Making sure to only apply the comma replace part on the first line. This can lead to problems though if your data is... inconsistent.
Hope this helps.

PHP remove all newlines and spaces from a csv

I am trying to convert a CSV to JSON using this awesome Jist: https://gist.github.com/robflaherty/1185299
I have been given a very CSV from a very antiquated procedural programming language. The CSV can ONLY be produced as follows.
I need to strip out the second line which is a blank newline and ideally, I'd like to strip out all the extra spaces for each line:
Series, SKU, Stock
01000 , 01000-1116 , 98
01000 , 01000-1132 , 0
01000 , 01000-116 , 1000
01000 , 01000-1164 , 3880
01000 , 01000-12 , 2040
01000 , 01000-132 , 2240
01000 , 01000-1332 , 545
01000 , 01000-1364 , 50
I've tried every combination in my small arsenal to get this to work. preg_replace, trim etc.
Has anyone got any advice? Here is the section of the Jist that is handling the rows:
function csvToArray($file, $delimiter) {
if (($handle = fopen($file, 'r')) !== FALSE) {
$i = 0;
while (($lineArray = fgetcsv($handle, 4000, $delimiter, '"')) !== FALSE) {
for ($j = 0; $j < count($lineArray); $j++) {
$arr[$i][$j] = $lineArray[$j];
}
$i++;
}
fclose($handle);
}
return $arr;
}
I hope someone can help! Thanks in advance for taking a look.
You need to check $lineArray and use trim() function as in the following code:
function csvToArray($file, $delimiter) {
if (($handle = fopen($file, 'r')) !== FALSE) {
$i = 0;
while (($lineArray = fgetcsv($handle, 4000, $delimiter, '"')) !== FALSE) {
if (count($lineArray) == 1 && is_null($lineArray[0])) {
continue;
}
for ($j = 0; $j < count($lineArray); $j++) {
$arr[$i][$j] = trim($lineArray[$j]);
}
$i++;
}
fclose($handle);
}
return $arr;
}
Try this. It skips empty lines and trims values.
// Function to convert CSV into associative array
function csvToArray($file, $delimiter) {
if (($handle = fopen($file, 'r')) !== FALSE) {
$i = 0;
while (($lineArray = fgetcsv($handle, 4000, $delimiter, '"')) !== FALSE) {
if(count($lineArray)==1) continue; //skip empty line (will fail if file will have only one column)
for ($j = 0; $j < count($lineArray); $j++) {
$arr[$i][$j] = trim($lineArray[$j]); //trim value
}
$i++;
}
fclose($handle);
}
return $arr;
}
Try this code:
function csvToArray($file, $delimiter)
{
if (($handle = fopen($file, 'r')) !== FALSE) {
$i = 0;
while (($lineArray = fgetcsv($handle, 4000, $delimiter, '"')) !== FALSE) {
for ($j = 0; $j < count($lineArray); $j++) {
if ($lineArray[$j] !== '') {
$arr[$i][$j] = $lineArray[$j];
}
}
$i++;
}
fclose($handle);
}
return $arr;
}

How to find string position php

I want to get the position of 'ja' in each of the words in $string, but its not working. what am i doing wrong?
<?php
$offset = 0;
$find = 'ja';
$find_length = strlen($find);
$string = 'jasim jasmin jassir';
while ($string_position = strpos($string, $find, $offer)) {
echo $find.' found at '.$string_position.'<br>';
$offset = $string_position + $find_length;
}
?>
Change the variable name to $offset
strpos may return 0 and while will treat it as false
So replace your while statement with:
while (($string_position = strpos($string, $find, $offset)) !== false) {
<?php
// stack overflow area
$offset = 0;
$find = 'ja';
$find_length = strlen($find);
$string = 'jasim jasmin jassir';
if (strpos($string, $find) === false) {
echo "not found";
}
else {
while (strpos($string, $find, $offset) !== false) {
$string_position = strpos($string, $find, $offset);
echo $find.' found at '.$string_position.'<br>';
$offset = $string_position + $find_length;
}
}
?>
Little workaround, but it apparently works.
Output:
ja found at 0
ja found at 6
ja found at 13
try changing offest
<?php
$offset = 1;
$find = 'ja';
$find_length = strlen($find);
$string = 'jasim jasmin jassir';
while ($string_position = strpos($string, $find, $offset)) {
echo $find.' found at '.$string_position.'<br>';
$offset = $string_position + $find_length;
}
?>
// output :- ja found at 6
ja found at 13
if you don't want to change offset use
$string = ' jasim jasmin jassir'; (without space not be jasim it's 'jasim )
then it will output 3
ja found at 1
ja found at 7
ja found at 14
OR try to change your condition check
while (($string_position = strpos($string, $find, $offset)) !== false) {
Probably you should code this way to find string positions
$positions = array();
$offset = -1;
while (($pos = strpos($string, $find, $offset+1)) !== false) {
$positions[] = $offset;
}
$result = implode(', ', $positions);
print this result

PHP - Returning the last line in a file?

I'm guessing it's fgets, but I can't find the specific syntax. I'm trying to read out (in a string I'm thinking is easier) the last line added to a log file.
The simplest naive solution is simply:
$file = "/path/to/file";
$data = file($file);
$line = $data[count($data)-1];
Though, this WILL load the whole file into memory. Possibly a problem (or not). A better solution is this:
$file = escapeshellarg($file); // for the security concious (should be everyone!)
$line = `tail -n 1 $file`;
This looks like it is what you are looking for:
tekkie.flashbit.net: Tail functionality in PHP
It implements a function that uses fseek() with a negative index to roll up the file from the end. You can define how many lines you want to be returned.
The code also is available as a Gist on GitHub:
// full path to text file
define("TEXT_FILE", "/home/www/default-error.log");
// number of lines to read from the end of file
define("LINES_COUNT", 10);
function read_file($file, $lines) {
//global $fsize;
$handle = fopen($file, "r");
$linecounter = $lines;
$pos = -2;
$beginning = false;
$text = array();
while ($linecounter > 0) {
$t = " ";
while ($t != "\n") {
if(fseek($handle, $pos, SEEK_END) == -1) {
$beginning = true;
break;
}
$t = fgetc($handle);
$pos --;
}
$linecounter --;
if ($beginning) {
rewind($handle);
}
$text[$lines-$linecounter-1] = fgets($handle);
if ($beginning) break;
}
fclose ($handle);
return array_reverse($text);
}
$fsize = round(filesize(TEXT_FILE)/1024/1024,2);
echo "<strong>".TEXT_FILE."</strong>\n\n";
echo "File size is {$fsize} megabytes\n\n";
echo "Last ".LINES_COUNT." lines of the file:\n\n";
$lines = read_file(TEXT_FILE, LINES_COUNT);
foreach ($lines as $line) {
echo $line;
}
define('YOUR_EOL', "\n");
$fp = fopen('yourfile.txt', 'r');
$pos = -1; $line = ''; $c = '';
do {
$line = $c . $line;
fseek($fp, $pos--, SEEK_END);
$c = fgetc($fp);
} while ($c != YOUR_EOL);
echo $line;
fclose($fp);
This is better, since it does not load the complete file into memory...
Set YOUR_EOL to your correct line endings, if you use the same line endings as the default line endings of the OS where your script resides, you could use the constant PHP_EOL.
function seekLastLine($f) {
$pos = -2;
do {
fseek($f, $pos--, SEEK_END);
$ch = fgetc($f);
} while ($ch != "\n");
}
-2 because last char can be \n
You either have to read the file in line by line and save the last read line to get it.
Or if on unix/linux you might consider using the shell command tail
tail -n 1 filename
This one wont break for a 1 or 0 line file.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
$begining = fseek($fp, 0);
$pos = -1;
$t = " ";
while ($t != "\n") {
fseek($fp, $pos, SEEK_END);
if(ftell($fp) == $begining){
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}
If you want to read a file line by line the file function reads the contents of a file, line by line and returns each line as an element of an array.
So you could do something simple like:
$lines = file('log.txt');
$lastLine = array_pop($lines);
...Why just read the last line?
function readLines($fp, $num) {
$line_count = 0; $line = ''; $pos = -1; $lines = array(); $c = '';
while($line_count < $num) {
$line = $c . $line;
fseek($fp, $pos--, SEEK_END);
$c = fgetc($fp);
if($c == "\n") { $line_count++; $lines[] = $line; $line = ''; $c = ''; }
}
return $lines;
}
$filename = "content.txt";
$fp = #fopen($filename, "r");
print_r(readLines($fp, 2));
fclose($fp);
#unique_stephen, your answer is flawed. PHP fseek returns 0 for success and -1 for failure. Storing the result in $begining (sic) and then later using it in a filter for ftell() isn't correct. If my reputation were higher I would have voted you down and left a comment. Here is a modified version of unique_stephen's function.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
if (fseek($fp, 0) == -1)
exit('Cannot seek to beginning of the file');
$pos = -1;
$t = " ";
while ($t != "\n") {
if (fseek($fp, $pos, SEEK_END) == -1)
exit('Cannot seek to the end of the file');
if (ftell($fp) == 0) {
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}
NOTE: PHP's fseek cannot manage to seek to the end of files larger than PHP_MAX_INT which is 32bit signed even on 64bit binaries.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
$begining = fseek($fp, 0);
$pos = -1;
$t = " ";
while ($t != "\n") {
fseek($fp, $pos, SEEK_END);
if(ftell($fp) == $begining){
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}

Categories