Manually move the fgetc file pointer to the next line - php

Question 1: How can I manually move the fgetc file pointer from its current location to the next line?
I'm reading in data character by character until a specified number of delimiters are counted. Once the delimiter count reaches a certain number, it needs to copy the remainder of the line until a new line (the record delimiter). Then I need to start copying character by character again starting at the next record.
Question 2: Is manually moving the file pointer to the next line the right idea? I would just explode(at "\n") but I have to count the pipe delimiters first because "\n" isn't always the record delimiter.
Here's my code (it puts all the data into the correct record until it reaches the last delimiter '|' in the record. It then puts the rest of the line into the next record because I haven't figured out how to make it correctly look for the '\n' after specified # of | are counted):
$file=fopen("source_data.txt","r") or exit ("File Open Error");
$record_incrementor = 0;
$pipe_counter = 0;
while (!feof($file))
{
$char_buffer = fgetc($file);
$str_buffer[] = $char_buffer;
if($char_buffer == '|')
{
$pipe_counter++;
}
if($pipe_counter == 46) //Maybe Change to 46
{
$database[$record_incrementor] = $str_buffer;
$record_incrementor++;
$str_buffer = NULL;
$pipe_counter = 0;
}
}
Sample Data:
1378|2009-12-13 11:51:45.783000000|"Pro" |"B13F28"||""|1||""|""|""|||False|||""|""|""|""||""||||||2010-12-15 11:51:51.330000000|108||||||""||||||False|""|""|False|""|||False
1379|2009-12-13 12:23:23.327000000|"TLUG"|"TUG"||""|1||""|""|""|||False|||""|""|""|""||""||||||1943-04-19 00:00:00|||||||""||||||False|""|""|False|""|||False

I'd say that doing this via file handling functions is a bit clumsy, when it could be done via regular expression quite easily. Just read the entire file into a string using file_get_contents() and doing a regular expression like /^(([^|]*\|){47}([^\r\n]*))/m with preg_match_all() could find you all the rows (which you can then explode() using | as the delimiter and setting 48 as the limit for number of fields.
Here is a working example function. The function takes the file name, field delimiter and the number of fields per row as the arguments. The function returns 2 dimensional array where first index is the data row number and the second is the field number.
function loadPipeData ($file, $delim = '|', $fieldCount = 48)
{
$contents = file_get_contents($file);
$d = preg_quote($delim, '/');
preg_match_all("/^(([^$d]*$d){" . ($fieldCount - 1) . '}([^\r\n]*))/m', $contents, $match);
$return = array();
foreach ($match[0] as $line)
{
$return[] = explode($delim, $line, $fieldCount);
}
return $return;
}
var_dump(loadPipeData('source_data.txt'));
(Note: this is a solution to the original problem)

You can read to the end of the line like this:
while (!feof($file) && fgetc($file) !== '\n');
As for whether or not fgetc is the right way to do this... your format makes it difficult to use anything else. You can't split on \n, because there may be newlines within a field, and you can't split on |, because the end of the record doesn't have a pipe.
The only other option I can think is to use preg_match_all:
$buffer = file_get_contents('test.txt');
preg_match_all('/((?:[^|]*\|){45}[^\n]*\n)/', $buffer, $matches);
foreach ($matches[0] as $row) {
$fields = explode('|', $row);
}

Answer to the modified question:
To read from the file pointer to the end of the line, you can simply use the file reading function fgets(). It returns everything from the current file pointer position until it reaches the end of the line (and also returns the end of the line character(s)). After the function call, the file reading pointer has been moved to the beginning of the next line.

Related

How to remove lines containing a specific character (#) from file and echo out the data using PHP

I have a text file with data that looks like this:
#dacdcadcasvsa
#svsdvsd
#
#sfcnakjncfkajnc
I want to keep this line
and this one
How can I remove all lines containing # and echo out the lines that don't so it looks like:
I want to keep this line
and this one
All I know is that I have to get_file_contents($filename). Would I have to put it in an array?
Any tips and guidance would be appreciated.
Using file() and foreach()
$lines = file("a.txt");
foreach ( $lines as $line ) {
if ( $line[0] != '#' ){
echo $line;
}
}
Just update the name of the file.
You can replace all the comment lines with empty strings before you output.
<div style="white-space: pre-line;">
<?= preg_replace('/^#.*\n/m', '', file_get_contents($filename)) ?>
</div>
You're thinking along the right lines; although the PHP method (function) you need is actually file_get_contents(), not get_file_contents() (as per your question).
Let's break it down:
We need a way of separating out our data into sortable chunks. As you stated, the best way to do this is using an array.
We could do this, using the hash symbol (#) as a delimiter - but this
would mean the last chunk of text is a mixture of text we want to
remove, and text we want to keep. Instead, we'll be using line
breaks as our delimiter.
Once the data has been separated, we can work on removing those lines that begin with a hash symbol.
Our code will look something like this:
<?php
// Get the file contents
$fileContents = file_get_contents('my_file.txt'); // This could be any file extension
// Split the file by new lines
$contentsArr = preg_split('/\r\n|\r|\n/', $fileContents);
// Function for removing items from an array - https://stackoverflow.com/questions/9993168/remove-item-from-array-if-item-value-contains-searched-string-character?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
function myFilter($string) {
return strpos($string, '?') === false;
}
// Remove comment items from array
$newFileContents = array_filter($fileContents, 'myFilter');
// Concatenate and echo out the result
echo implode(",\n",$newFileContents);
An alternate because I was bored:
foreach(preg_grep('/^#/', file($filename), PREG_GREP_INVERT) as $line) {
echo $line;
}
Read file lines into an array
Get all lines NOT starting with ^ the # character
Loop those lines

Using array_push to append to end of a desired line (PHP)

So I'm trying to append a string at the end of a row. The row and the string is inputted by the user.
//irrelevant...
$row = $_POST["whichRow"];
$Comment = $_POST["stringValue"];
$lines = array();
$arrayWithComment = array(";", "$actualComment");
$lineCount = 0;
foreach(file('/var/www/html/bkbpNew/tickets.csv') as $line){
if ($lineCount == $row){
array_push($lines, $line, $arrayWithComment[0], $arrayWithComment[1]);}
else{
array_push($lines, $line);}
$lineCount++;
}
file_put_contents('/var/www/html/bkbpNew/tickets.csv', $lines);
And that sort of works, but not in the way that I want it to. Here is the edited file before/after & the desired state:
(Input values for this example are comment = "test" and row = 2)
Desired result of edited file:
1;example;example;example;example;example;example
2;example;example;example;example;example;example;test
3;example;example;example;example;example;example
Edited file BEFORE the above code is executed:
1;example;example;example;example;example;example
2;example;example;example;example;example;example
3;example;example;example;example;example;example
Edited file AFTER the above code is executed:
1;example;example;example;example;example;example
2;example;example;example;example;example;example
;test3;example;example;example;example;example;example
it automatically goes into the next line (Desired result) but I don't want it to. How do I go about this? Cheers!
when you use file(), newline characters are included at the end of the line, so when you're adding your new comment to the end of the line you're adding it after the new line character
I'm not a big fan of your approach to this, but as a quick and dirty solution use the FILE_IGNORE_NEW_LINES flag for file(), and then manually re-add the newline characters for each line in your loop

php - regex exact matches

I have the following strings:
Falchion-Case
P90-ASH-WOOD-WELL-WORN
I also have the following URLS which are inside a text file:
http://csgo.steamanalyst.com/id/115714004/FALCHION-CASE-KEY-
http://csgo.steamanalyst.com/id/115716486/FALCHION-CASE-
http://csgo.steamanalyst.com/id/2018/P90-ASH-WOOD-WELL-WORN
I'm looping through each line in the text file and checking if the string is found inside the URL:
// Read from file
if (stristr($item, "stattrak") === FALSE) {
$lines = file(public_path().'/csgoanalyst.txt');
foreach ($lines as $line) {
// Check if the line contains the string we're looking for, and print if it does
if(preg_match('/(?<!\-)('.$item.')\b/',$line) != false) { // case insensitive
echo $line;
break;
}
}
}
This works perfectly when $item = P90-ASH-WOOD-WELL-WORN however when $item = Falchion-Case It matches on both URL's when only the second: http://csgo.steamanalyst.com/id/115716486/FALCHION-CASE- is valid
Try modifying your regx to match the end of the line, assuming the line ends
'/('.$item.')$/'
This would match
http://csgo.steamanalyst.com/id/115714004/FALCHION-CASE-KEY- <<end of line
Basically do an ends with type match, you can do this too
'/('.$item.')\-?$/'
to optionally match an ending hyphen
You can also use a negative lookahead to negate that unwanted case:
preg_match('/(?<!-)'. preg_quote($item) .'(?!-\w)/i', $line);

explode csv file on delimiter (;) and delimiter(,)?

when I explode csv file on delimiter (;)
the explode successfully in some excel program and failed in others
also when I explode csv file on delimiter (,)
the explode successfully in some excel program and failed in others
How can I do explode in all versions of excel?
How can I know the perfect delimiter to explode?
yes there is code..
if (!function_exists('create_csv')) {
function create_csv($query, &$filename = false, $old_csv = false) {
if(!$filename) $filename = "data_export_".date("Y-m-d").".csv";
$ci = &get_instance();
$ci->load->helper('download');
$ci->load->dbutil();
$delimiter = ";";
$newline = "\r\n";
$csv = "Data:".date("Y-m-d").$newline;
if($old_csv)
$csv .= $old_csv;
else
$csv .= $ci->dbutil->csv_from_result($query, $delimiter, $newline);
$columns = explode($newline, $csv);
$titles = explode($delimiter, $columns[1]);
$new_titles = array();
foreach ($titles as $item) {
array_push($new_titles, lang(trim($item,'"')));
}
$columns[1] = implode($delimiter, $new_titles);
$csv = implode($newline, $columns);
return $csv;
}
}
sometimes I put $delimiter = ";";
and sometims $delimiter = ",";
thanks..
You can use helper function to detect best delimiter like:
public function find_delimiter($csv)
{
$delimiters = array(',', '.', ';');
$bestDelimiter = false;
$count = 0;
foreach ($delimiters as $delimiter)
if (substr_count($csv, $delimiter) > $count) {
$count = substr_count($csv, $delimiter);
$bestDelimiter = $delimiter;
}
return $bestDelimiter;
}
If you have an idea of the expected data (number of columns) then this might work as a good guess, and could be a good alternative to comparing which occurs the most (depending on what kind of data you're expecting).
It would work even better if you have a header record, I'd imagine. (You could put in a check for specific header values)
Sorry for not fitting it into your code, but I am not really sure what those calls you are making do, but you should be able to fit it around.
$expected_num_of_columns = 10;
$delimiter = "";
foreach (array(",", ";") as $test_delimiter) {
$fid = fopen ($filename, "r");
$csv_row = fgetcsv($fid, 0, $test_delimiter);
if (count($csv_row) == $expected_num_of_columns) {
$delimiter = $test_delimiter;
break;
}
fclose($fid);
}
if (empty($delimiter)) {
die ("Input file did not contain the correct number of fields (" . $expected_num_of_columns . ")");
}
Don't use this if, for example, all or most of the fields contain non-integer numbers (e.g. a list of monetary amounts) and has no header record, because files separated by ; are most likely to use , as the decimal point and there could be the same number of commas and semi-colons.
The short answer is, you probably can't unless you can apply some heuristic to determine the file format. If you don't know and can't detect the format of the file you're parsing, then parsing it is going to be difficult.
However, once you have determined (or, required a particular one) the delimiter format. You will probably find that php's built-in fgetcsv will be easier and more accurate than a manual explode based strategy.
There is no way to be 100% sure you are targeting the real delimiter. All you can do is guessing.
You should start by finding the right delimiter, then explode the CSV on this delimiter.
To find the delimiter, basically, you want a function that counts the number of , and the number of ; and that returns the greater.
Something like :
$array = explode(find_delimiter($csv), $csv);
Hope it helps ;)
Edit : Your find_delimiter function could be something like :
function find_delimiter($csv)
{
$arrDelimiters = array(',', '.', ';');
$arrResults = array();
foreach ($arrDelimiters as $delimiter)
{
$arrResults[$delimiter] = count(explode($delimiter, $csv));
}
$arrResults = rsort($arrResults);
return (array_keys($arrResults)[0]);
}
Well, it looks like you exactly know that your delimiter will be "," or ";". This is a good place to start. Thus, you may try to replace all commas (,) to semicolons (;), and then explode by the semicolon only. However, in this approach you would definitely have a problem in some cases, because some lines of your CSV files could be like this:
"name,value",other name,other value,last name;last value
In this way delimiter of your CSV file will be comma if there will be four columns in your CSV file. However, by changing commas to semicolons you would get five columns which would be incorrect. So, changing some delimiter to another is not a good way.
But still, if your CSV file is correctly formatted, then you may find correct delimiter in any of the lines. So, you may try to create some function like find_delimiter($csvLine) as proposed by #johnkork, but the problem with this is that the function itself can't know which delimiter to search for. However, you exactly know all the possible delimiters, so you may try to create another, quite similar, function like delimiter_exists($csvLine, $delimiter) which returns true or false.
But even the function delimiter_exists($csvLine, $delimiter) is not enough. Why? Because for the instance of CSV line provided above you would get that both "," and ";" are delimiters that exists. For comma it would CSV file with four columns, and for semicolon it would be two columns.
Thus, there is no universal way which would get you exactly what you want. However, there may be another way you can check for - the first line of CSV file which is the header assuming your CSV files have a header. Mostly, headers in CSV file have (not necessarily) no other symbols, except for the alphanumeric names of the columns, which are delimited by the specific delimiter. So, you may try to create function like delimiter_exists($csvHeader, $delimiter) whose implementation could be like this:
function delimiter_exists($csvHeader, $delimiter) {
return (bool)preg_match("/$delimiter/", $csvHeader);
}
For you specific case you may use it like this:
$csvHeader = "abc;def";
$delimiter = delimiter_exists($csvHeader, ',') ? ',' : ';';
Hope this helps!

Remove new lines from data retrived from text file using PHP

I have following data in text file
375020222511963
284970411563422
290245594366931
I need to retrieve a random variable from the above text file.
I use the following php code to do that
<?php
$file = file("file.txt");
$len = count($file);
$rand = rand ( 0, $len-1 );
echo $file[$rand];
?>
But it's returning new line along with the retrieved data. I need to retrieve data without new line.
The file() function has an optional second argument taking a bit mask of flags which affect what is returned in the array.
Available flags are FILE_USE_INCLUDE_PATH, FILE_IGNORE_NEW_LINES, and SKIP_EMPTY_LINES. The FILE_IGNORE_NEW_LINES is the one that you want to use in order to have each line in the array not include the trailing newline character.
So, your line of code should look like the following.
$file = file("file.txt", FILE_IGNORE_NEW_LINES);
Descriptions and more info, see http://php.net/file.
Change last line to:
echo trim($file[$rand]);
trim() removes white-spaces (blanks, new lines, tabs) from the beginning and end of a string.
In order to avoid empty lines... If the last line is always the only empty one:
$rand = rand (0, $len - 2); // Instead of -1
Else, if you can have empty lines everywhere, replace the last two lines of code with:
do {
$rand = rand (0, $len - 1);
} while (trim($file[$rand]) == '');
echo $file[$rand];

Categories