I have a text file with multiple rows and columns inside them.
I want to read each and every row and column, store them in array and save all data in database using cakephp.
Below is my code, I wrote some row and column reading logic which i wants to implement.
Please help me to do this critical thing.
public function importfile(){
$fp = 'C:/wamp64/www/jhraut/webroot/uploads/120518SU';
$handle = fopen($fp, "r");
if ($handle) {
while (($line = fgetc($handle)) !== false) {
$data['GunNo'] = "first 5 characters of $line is GunNo than 1 character is space";
$data['FatGun'] = "Second 3 characters of $line is FatGun than 1 character is space";
$data['LoinGun'] = "Third 3 characters of $line is LoinGun than 1 character is space";
$data['ScaleWt'] = "fourth 5 characters of $line is ScaleWt than 1 character is space";
$data['Partial'] = "if P or M than 1 character is space";
$data['TimeofReading'] = "last 8 characters of $line is TimeofReading";
echo $line;
}
$this->Event_program->saveAll($data);
}
fclose($fp);
exit;
}
My file data
parti 011 058 145.6 P 06:37:01
00002 016 049 175.8 06:37:08
00003 009 072 150.8 06:37:15
00004 009 053 146.8 06:37:22
00005 011 054 169 06:37:29
00006 009 052 152.4 06:37:37
00007 018 059 194.8 06:37:44
00008 009 060 139.4 06:37:51
parti 008 069 134.8 P 06:37:58
00010 023 054 194.2 06:38:05
miss 197.2 06:38:13
00011 023 052 150 06:38:20
00012 008 059 146.6 06:38:27
00013 010 067 156 06:38:34
00014 013 049 190.8 06:38:41
Try something like this:
// set path to file
$file = WWW_ROOT.'uploads/120518SU';
// check if file exists
if (file_exists($file)) {
// Reads an entire file into an array with file() method
// and loop array
foreach (file($file) as $line) {
// convert line value to new array
$arr = explode(' ', $line);
// do something with your data..
$data = [
'GunNo' => $arr[0],
// ...
];
$entity = $this->EventProgram->newEntity($data);
$this->EventProgram->save($entity);
}
}
Update with some test:
$line = '00003 009 072 150.8 06:37:15';
$arr = explode(' ', $line);
print_r($arr);
// output
Array
(
[0] => 00003
[1] => 009
[2] => 072
[3] => 150.8
[4] =>
[5] =>
[6] =>
[7] => 06:37:15
)
$line = 'parti 008 069 134.8 P 06:37:58';
// ..
Array
(
[0] => parti
[1] => 008
[2] => 069
[3] => 134.8
[4] => P
[5] =>
[6] => 06:37:58
)
Then:
// do something with your data..
$data = [
// ...
'TimeofReading' => end($arr),
];
Update: reading as csv file
Use fgetcsv()
The fgetcsv() function parses a line from an open file, checking for
CSV fields.
The fgetcsv() function stops returning on a new line, at the specified
length, or at EOF, whichever comes first.
This function returns the CSV fields in an array on success, or FALSE
on failure and EOF.
fgetcsv(file,length,separator,enclosure);
Use regular expression. As you have some rows having few fields empty splitting with space might cause problem.
preg_match('/(.{5}) (.{3}) (.{3}) (.{5}) (.{1}) (.{8})/', $line, $op);
$data['GunNo'] = $op[1];
$data['FatGun'] = $op[2];
$data['LoinGun'] = $op[3];
$data['ScaleWt'] = $op[4];
$data['Partial'] = $op[5];
$data['TimeofReading'] = $op[6];
echo $op[0];
You can teds regular expression line on
https://www.phpliveregex.com/#tab-preg-match
Related
My file is like this
row 1: 1,2,3,4
row 2: bob,larry,jill, "sue
she is a great girl"
row3 3:tom, fred, jack, billy
when I use fgetcsv($handle,0,',','"') it breaks up row 2 into two separate rows because column 4 has a \n in it. The people who are giving me these csv are using excel to do it and excel is only enclosing with double quotes when there is a special character.
How can I write fgetcsv() so that it does not break on \n that are inside of double quotes? I am writing very heavy PHP and am parsing sometimes millions of rows so my solution has to be memory and time efficient. It just seems to me that I must be using fgetcsv wrong because it should obviously not be breaking on an enclosed \n.
I have the code:
$row = 1;
if (($handle = fopen("test.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",", '"')) !== FALSE) {
print_r($data);
}
fclose($handle);
}
and the test.csv:
1,2,3,4
bob,larry,jill, "sue
she is a great girl"
tom, fred, jack, billy
the result is as excepted:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
Array
(
[0] => bob
[1] => larry
[2] => jill
[3] => sue
she is a great girl
)
Array
(
[0] => tom
[1] => fred
[2] => jack
[3] => billy
)
your file must be:
1,2,3,4
bob,larry,jill, "sue
she is a great girl"
tom, fred, jack, billy
without \n in it
I need to pass the data to an array by blocks, how can I make this? Do I need to use regex? My script gives me errors because I can not separate it as I wish. Does anyone have any ideas?
Data:
~0
11111111
~1
222222222
~2
3333333333
~end
~0
aaaaaaaaaaa
~1
bbbbbbbbbb
~2
cccccccccc
~3
ddddddddddd
~end
~0
yyyyyyyyyyy
xxxxxxxx
ffffffffff
~1
rrrrrrrrrrrr
~end
I need it like this:
Array (
[0] => Array
(
[0] => 11111111
[1] => 222222222
[2] => 3333333333
)
),
[1] => Array
(
[0] => aaaaaaaaaaa
[1] => bbbbbbbbbb
[2] => cccccccccc
[3] => ddddddddddd
)
),
[2] => Array
(
[0] => yyyyyyyyyyy
xxxxxxxx
ffffffffff
[1] => rrrrrrrrrrrr
)
),
)
My code (Fail):
$texto = "~0
11111111
~1
222222222
~2
3333333333
~end
~0
aaaaaaaaaaa
~1
bbbbbbbbbb
~2
cccccccccc
~3
ddddddddddd
~end
~0
yyyyyyyyyyy
xxxxxxxx
ffffffffff
~1
rrrrrrrrrrrr
~end";
preg_match_all("/(?ms)^~0.*?~end/", $texto, $coincidencias);
foreach ( $coincidencias[0] as $bloque ){
preg_match_all("/\~.*\n/", $bloque, $sub_bloques);
$hola[] = $sub_bloques;
}
Here is one non-regex way: split the string into lines and iterate over them. Check for the conditions you've specified and add each line to a sub-array if it meets the conditions. Then when you get to an ~end line, append the sub-array to the main array.
$sub_bloques = [];
$hola = [];
foreach(array_map('trim', explode("\n", $texto)) as $line) {
if ($line && substr($line, 0, 1) !== '~') {
$sub_bloques[] = $line;
}
if ($line == '~end') {
$hola[] = $sub_bloques;
$sub_bloques = [];
}
}
For a regex solution, start by exploding on ~end to break the main text into sections, then preg_match_all on the sections to find lines that meet your conditions.
foreach (explode('~end', $texto, -1) as $section) {
preg_match_all('/\n *(?!~)(\w+)/', $section, $matches);
if ($matches[1]) $result[] = $matches[1];
}
(?!~) is a a negative lookbehind to exclude lines that start with ~. Maybe there's some way to do the whole thing with one big cool regex, but I'm not that good at it.
Because you want to have your sub-blocks separated into blocks in your output array, there needs to be two-steps in the method. The reason is that your sub-blocks have differing capture group counts and regex will not permit this variability.
Code:
// This delivers the sub-blocks in their relative blocks as requested in the OP
foreach (preg_split('/\s+~end\s*/',$texto) as $bloque) {
if(preg_match_all('/(?:\~\d+\s+)\K.+?(?:\s+\S+)*?(?=\s+\~|$)/',$bloque,$sub_bloques)){
$hola[]=$sub_bloques[0];
}
}
var_export($hola);
Output *reformatted/condensed to save space on this page (View Demo):
array(
array('11111111','222222222','3333333333'),
array('aaaaaaaaaaa','bbbbbbbbbb','cccccccccc','ddddddddddd'),
array('yyyyyyyyyyy
xxxxxxxx
ffffffffff','rrrrrrrrrrrr')
)
Alternatively, if you want to have all sub-blocks listed in a 1-dim array (not divided by blocks) the output array can be built in one step:
if(preg_match_all("/(?:\~\d+\s*)\K.+?(?:\s+\S+)*?(?=\s+\~)/s", $texto, $coincidencias)){
var_export($coincidencias[0]);
}
1-dim output:
array (
0 => '11111111',
1 => '222222222',
2 => '3333333333',
3 => 'aaaaaaaaaaa',
4 => 'bbbbbbbbbb',
5 => 'cccccccccc',
6 => 'ddddddddddd',
7 => 'yyyyyyyyyyy
xxxxxxxx
ffffffffff',
8 => 'rrrrrrrrrrrr',
)
I need to split the string bellow into array keys like in this format:
string = "(731) some text here with number 2 (220) some 54 number other text here" convert into:
array(
'731' => 'some text here with number 2',
'220' => 'some 54 number other text here'
);
I have tried:
preg_split( '/\([0-9]{3}\)/', $string );
and got:
array (
0 => 'some text here',
1 => 'some other text here'
);
Code
$string = "(731) some text here with number 2 (220) some 54 number other text here";
preg_match_all("/\((\d{3})\) *([^( ]*(?> +[^( ]+)*)/", $string, $matches);
$result = array_combine($matches[1], $matches[2]);
var_dump($result);
Output
array(2) {
[731]=>
string(28) "some text here with number 2"
[220]=>
string(30) "some 54 number other text here"
}
ideone demo
Description
The regex uses
\((\d{3})\) to match 3 digits in parentheses and captures it (group 1)
\ * to match the spaces in between keys and values
([^( ]*(?> +[^( ]+)*) to match everything except a ( and captures it (group 2)
This subpattern matches exactly the same as [^(]*(?<! ) but more efficiently, based on the unrolling-the-loop technique.
*Notice though that I am interpreting a value field cannot have a ( within. If that is not the case, do tell and I will modify it accordingly.
After that, we have $matches[1] with keys and $matches[2] with values. Using array_combine() we generate the desired array.
Try this:
$string = "(731) some text here with number 2 (220) some 54 number other text here";
$a = preg_split('/\s(?=\()/', $string);//split by spaces preceding the left bracket
$res = array();
foreach($a as $v){
$r = preg_split('/(?<=\))\s/', $v);//split by spaces following the right bracket
if(isset($r[0]) && isset($r[1])){
$res[trim($r[0],'() ')] = trim($r[1]);//trim brackets and spaces
}
}
print_r($res);
Output:
Array
(
[731] => some text here with number 2
[220] => some 54 number other text here
)
DEMO
If you want to limit it only to those numbers in brackets that have 3 digits, just modify the lookarounds:
$a = preg_split('/\s(?=\([0-9]{3}\))/', $string);
you can try this one,
<?php
$str="(731) some text here (220) some other text here";
echo $str .'<br>';
$arr1=explode('(', $str);
$size_arr=count($arr1);
$final_arr=array();
for($i=1;$i<$size_arr; $i++){
$arr2=explode(')', $arr1[$i]);
$final_arr[$arr2[0]]=trim($arr2[1]);
}
echo '<pre>';
print_r($final_arr);
?>
Use this link to test the code, Click Here.
I try to use the simple syntax. Hope everybody can understand.
I'm pretty sure that defining the keys is not possible, as the regex will add matches coninuously.
I would define 2 regex,
one for the keys:
preg_match_all("/(\()([0-9]*)(\))\s/", $input_lines, $output_array);
you will find your keys in $output_array[2].
And one for the texts (that looks quite the same):
preg_split("/(\()([0-9]*)(\))\s/", $input_line);
After that, you can build your custom array iterating over both.
Make sure to trim the strings in the second array when inserting.
Using preg_replace_callback() you can quickly achieve what you desire (when only parentheses contain 3 digits):
$string = "(731) some text here with number 2 (220) some 54 number other text here";
$array = array();
preg_replace_callback('~(\((\d{3})\))(.*?)(?=(?1)|\Z)~s', function($match) use (&$array) {
$array[$match[2]] = trim($match[3]);
}, $string);
var_dump($array);
Output:
array(2) {
[731]=>
string(28) "some text here with number 2"
[220]=>
string(30) "some 54 number other text here"
}
Maybe you can add PREG_SPLIT_DELIM_CAPTURE flag to preg_split. From preg_split man page (http://php.net/manual/en/function.preg-split.php)
PREG_SPLIT_DELIM_CAPTURE
If this flag is set, parenthesized expression in the delimiter pattern will be captured and returned as well.
So if you change your code to:
$results = preg_split('/\(([0-9]+)\)/s', $data,null,PREG_SPLIT_DELIM_CAPTURE);
You will obtain an array similar to:
Array
(
[0] => KS/M/ 2013/1238
[1] => 220
[2] => 23/12/2013
[3] => 300
[4] =>
[5] => 731
[6] => VALDETE BUZA ADEM JASHARI- PRIZREN, KS
[7] => 526
[8] =>
[9] => 591
[10] =>
[11] => 740
[12] =>
[13] => 540
[14] => DEINA
[15] => 546
[16] =>
[17] => 511
[18] => 3 Preparatet për zbardhim dhe substancat tjera për larje rrobash; preparatet për pastrim, shkëlqim, fërkim dhe gërryerje; sapunët; parfumet, vajrat esencialë, preparatet kozmetike, losionet për flokë, pasta për dhembe
14 Metalet e cmueshme dhe aliazhet e tyre; mallrat në metale të cmueshme ose të veshura me to, që nuk janë përfshire në klasat tjera; xhevahirët, gurët e cmueshëm; instrumentet horologjike dhe kronometrike (për matjen dhe regjistrimin e kohës)
25 Rrobat, këpucët, kapelat
35 Reklamim, menaxhim biznesi; administrim biznesi; funksione zyre
)
What you should do is to loop over the array ignoring first element in that case:
$myArray = array();
$myKey = '';
foreach ($results as $k => $v) {
if ( ($k > 0) && ($myKey == '')) {
$myKey = $v;
} else if ($k > 0) {
$myArray[$myKey] = $v;
$myKey = '';
}
}
EDIT: This answer is for:
$data ='KS/M/ 2013/1238 (220) 23/12/2013 (300)
(731) VALDETE BUZA ADEM JASHARI- PRIZREN, KS (526)
(591)
(740)
(540) DEINA (546)
(511) 3 Preparatet për zbardhim dhe substancat tjera për larje rrobash; preparatet për pastrim, shkëlqim, fërkim dhe gërryerje; sapunët; parfumet, vajrat esencialë, preparatet kozmetike, losionet për flokë, pasta për dhembe
14 Metalet e cmueshme dhe aliazhet e tyre; mallrat në metale të cmueshme ose të veshura me to, që nuk janë përfshire në klasat tjera; xhevahirët, gurët e cmueshëm; instrumentet horologjike dhe kronometrike (për matjen dhe regjistrimin e kohës)
25 Rrobat, këpucët, kapelat
35 Reklamim, menaxhim biznesi; administrim biznesi; funksione zyre';
In a school work, I built a site for a fictional space museum in my city using PHP. It has a Data Inclusion and Data Consultation systems, but I have a problem with the consultation that I want to know how to solve: how to delete the last line break from the file?
Data Inclusion
In the restricted area of the site, I have a HTML5 form with 5 fields (name, addres, telephone number, sex and visited exhibitions) that sends the data by the method POST to a function in PHP that writes it on a given txt file by using the fwrite command:
fwrite ($pointer, "$name | $addres | $telephone | $sex | $exhibitions " .PHP_EOL);
As you can see, it writes in a txt file the data entered on the form, plus a line break. The pointer is the variable used by fopen to open the file that I need to work. Example of output:
Márcio Aguiar | Belmiro Braga Street | 1234-5678 | M | Planets of Solar System
Joana Tobias | Santos Dummont Avenue | 8765-4321 | F | Black Holes, Satellites
Data Consultation
Then there is a consultation system. It has a loop that runs until the file ends. Inside this loop there is a variable named $buffer that gets one line of the txt file each time. It is then exploded to create a array named $lines[$counter]. To print it nicely, I use a array_combine where I join the names of the fields on another array ($keys) to the values written in $lines[$counter], and attibutes that to $combined[$counter]. Then the loop ends and I use a print_r inside <pre></pre> to see the data written in $combined, while mantaining the spaces and breaks that HTML would otherwise ignore. Here is the code:
$keys = array ("Name", "Address", "Telephone", "Sex", "Visited exhibition");
for ($counter=0;!feof($reader);$counter++){
$buffer = fgets($reader);
$lines[$counter] = explode(" | ", $buffer);
$combined[$counter] = array_combine($keys, $lines[$counter]);
}
echo "<pre>";
print_r($combined);
echo "</pre>";
Example of output:
Array
(
[0] => Array
(
[Name] => Márcio Aguiar
[Address] => Belmiro Braga Street
[Telephone] => 1234-5678
[Sex] => M
[Visited exhibitions] => Planets of Solar System
)
[1] => Array
(
[Name] => Joana Tobias
[Address] => Santos Dummont Avenue
[Telephone] => 8765-4321
[Sex] => F
[Visited exhibitions] => Black Holes, Satellites
)
[2] =>
)
Here you can see that a 2 Array was created blank. It's caused by the last line, that contains only a line break inserted by the form above. I need to remove this last line break, and only that one, but don't know how. I want to know! Not knowing causes the exhibition of an error when the execution arrive at the array_combine, because it's needed that the two arrays have the same number of elements, and 2 is blank. Here the error:
Warning: array_combine(): Both parameters should have an equal number of elements in E:\Aluno\Documents\Wamp\www\trab_1\area_restrita\consulta.php on line 60
Original answer:
To remove a trailing line break from any text, you can use trim(), however in your case, you just need to use fopen in append mode:
$handle = fopen("/path/to/file", "a");
Then get rid of the PHP_EOL:
fwrite ($pointer, "$name | $addres | $telephone | $sex | $exhibitions");
Edit: You're right that appending doesn't append to a new line. I was mistaken. So you could use trim() like I mentioned earlier. I created a quick example using file_get_contents() and file_put_contents() and it appears to do what you want:
<?php
$file = 'test.txt';
// Set existing contents (for testing sake)
$orig_contents = "bob | 123 fake street | 1234567890 | yes, please | no\n";
$orig_contents .= "bob | 123 fake street | 1234567890 | yes, please | no\n";
$orig_contents .= "bob | 123 fake street | 1234567890 | yes, please | no\n";
$orig_contents .= "bob | 123 fake street | 1234567890 | yes, please | no\n";
file_put_contents($file, $orig_contents);
// Here is how you could add a single new line with append mode
// Notice the trailing \n
file_put_contents($file, "billy | 456 fake street | 2345678901 | no | yes\n", FILE_APPEND);
// Get contents from the file and remove any trailing line breaks
$contents = trim(file_get_contents($file));
$keys = array ("Name", "Address", "Telephone", "Sex", "Visited exhibition");
// Explode based on the new line character
$lines = explode("\n", $contents);
foreach ($lines as $line) {
$values = explode(" | ", $line);
$combined[] = array_combine($keys, $values);
}
print_r($combined);
This prints:
Array
(
[0] => Array
(
[Name] => bob
[Address] => 123 fake street
[Telephone] => 1234567890
[Sex] => yes, please
[Visited exhibition] => no
)
[1] => Array
(
[Name] => bob
[Address] => 123 fake street
[Telephone] => 1234567890
[Sex] => yes, please
[Visited exhibition] => no
)
[2] => Array
(
[Name] => bob
[Address] => 123 fake street
[Telephone] => 1234567890
[Sex] => yes, please
[Visited exhibition] => no
)
[3] => Array
(
[Name] => bob
[Address] => 123 fake street
[Telephone] => 1234567890
[Sex] => yes, please
[Visited exhibition] => no
)
[4] => Array
(
[Name] => billy
[Address] => 456 fake street
[Telephone] => 2345678901
[Sex] => no
[Visited exhibition] => yes
)
)
The problem is with the way you're reading the file. You're testing for EOF before reading from the file. But feof() won't be true until you try to read while you're at the end of the file.
Instead, you should test whether fgets() returns a line.
for ($counter = 0; $buffer = fgets($reader); $counter++) {
$lines[$counter] = explode(" | ", $buffer);
$combined[$counter] = array_combine($keys, $lines[$counter]);
}
DEMO
To explain further, suppose you have a file with one line in it. When $counter is 0, you call feof(), and it returns false. So you then read the first line, and add it to $lines and $combined. Then you increment $counter and go back to the beginning of the loop.
When $counter is 1, you call feof(). It's still not true, because you haven't tried to read at the end of the file yet. Then you try to read the next line, but there is no line there, fgets returns false and you assign this to $buffer. This is treated as an empty string by explode(), so you add an empty array to $lines and $combined. Then you increment $counter and go back to the beginning of the loop.
Then you call feof(), and this time it returns true because you tried to read at the end of the file on the previous iteration. So the loop ends.
As you can see from the above, even though the file only has 1 line, you end up with 2 entries in your arrays, because you didn't test for EOF until after you read too far.
In case you want to get rid of the last line break in data you pulled from the db ($res) you can use the following snippet
for ($i=0; $i <count($res); $i++) {
// If this is not last item then add items separated by line break
if($i+1 < count($res)) {
file_put_contents("file.txt", $res[$i].PHP_EOL, FILE_APPEND);
}
// If this is the last item, then don't append the final line break
else {
file_put_contents("file.txt", $res[$i], FILE_APPEND);
}
}
$filename = 'itunes_report.txt';
$f = fopen($filename, 'r');
$db = array();
$dbSize = 0;
$var = file($filename);
$mydata = trim($var[1]);
$temp = explode(" ", $mydata);
print_r($temp);
i read data from a file using this code. i was take the first line from the text file.
this is the line
APPLE US ebookReaderipad EC Media (International) Pvt. ltd BooksOnwink 1.3 1F 1 0 07/30/2012 08/05/2012 GBP GB GBP 425105344 0
i explode this line using white spaces. Then some white spaces are missing in output.
out put
Array ( [0] => APPLE US ebookReaderipad EC [1] => Media [2] => (International) [3] => Pvt. [4] => ltd BooksOnwink 1.3 1F 1 0 07/30/2012 08/05/2012 GBP GB GBP 425105344 0 )
Your input seem to be is tab \t delimited, you can split on "\t":
$temp = explode("\t", $mydata);
or if you are really mean to split on every whitespace, try using a more flexible spit with regexps:
$temp = preg_split('/\s+/', $mydata);
This will split on everything considered whitespace and consume sequence of whitespaces too.