Regarding to fgetcsv() documentation, there are some parameteres inside fgetcsv() function: Handle, length, delimiter, enclosure, and escape.
Now, I have 2 questions:
What does enclosure do exactly?
I have a csv file with 5 columns per line. Imagine it something like this: 1,2,3,4,5
So indexes are from 0 to 4. But whenever I want to get date from index 4, an empty value returns. Unless I put a comma after it (by filling an extra column after it that makes the contents like this: 1,2,3,4,5,6 ). How can I solve this issue ? It seems that there is some problem because of missing comma after the last item in each row of csv file!
1. The enclosure parameter is the character the encapsulates the data for a specific field, or "index". By default, the parameter is a ", which means that you can "enclose" strings in " characters.
Example:
1,2,"this is three",4
2. Per a comment, you're calling fgetcsv($handle, 10000, ','). It's possible, maybe, that the line(s) you're reading are longer than 10000 characters. Try changing the length to 0, which will be "no limit" and see if that helps. Another solution would be to try wrapping the column's value in double-quotes.
Enclosure is the character enclosing the field. It is an extra delimiter, of a sort.
For example hello,world has a comma as field delimiter, and has no text delimiter, while "hello","world" has a quote sign as text delimiter. Some systems employ delimited and undelimited values to indicate text and numeric fields, respectively (I believe Microsoft Excel does). This allows a field to contain the field delimiter in its value:
"Hello,world","Second Field","Third, and last, field".
Some other systems only enclose values containing the field delimiter, or values containing whitespace, which means that on those systems an undelimited value is not necessarily numeric.
If you have a "trivial" case - undelimited values, without escaped field-delimiters inside values (i.e., no 'A,firstpartB\,secondpartB,C' stuff) - you might skip CSV conversion altogether and run
$line = fgets($file, MAX_EXPECTED_LINE_LEN);
// This splits ' A, B, C ' into 'A', ' B' and ' C' (note spaces)
$row = explode(',', trim($line)); // other delimiters can be used
or
// Consider " , ", "," and ", " as the same delimiter
// i.e. ' Alpha , Beta , Gamma ' gets split into 'Alpha', 'Beta' and 'Gamma'
$row = preg_split('#\\s*,\\s*#', trim($line));
I cannot seem to reproduce the problem you are experiencing; could it be related to a different encoding of line endings (i.e., CRLF instead of LF)?
In a pinch, you can divide fgetcsv in the two components fgets and str_getcsv(), manipulating the line between the calls (with trim, or if the worse comes to the worst, by appending the missing comma).
It works to me on this way:
while ($row = $stmt -> fecht()){
echo "\"";
echo $row['email'];
echo "\"";
// Export every row to a file
$arr = array(',');
fputcsv($data, $arr, ";", '"' );
}
Related
I have below code in my script.
$file= fopen("./test.csv","x+");
$proj_lists="name,age,address,city name,country name\n";
fputcsv($file,explode(',',$proj_lists),',',' ');
fclose($file);
It creates a csv file with the given values.
My problem here is it creates extra space with double word.
Example "country name" is written as "country name"(2 spaces in this word).
How to resolve this.
My problem here is it creates extra space with double word
That's because you chose to use a space as the string enclosure character (4th argument, default value is a double quote). Here's the first line of the output:
name,age,address, city name , country name
^ ^^ ^ ^ ^^
e ee e e ee
Where e is the enclosure, and ee is the escaped enclosure, which is the escape character followed by the enclosure character (which happens to be part of the data you're trying to output).
It's best to simply use the defaults that come with fputcsv; that is, call the function with only two arguments.
fputcsv($file, explode(',', $proj_lists));
Which will output what most spreadsheet applications can read:
name,age,address,"city""name","country name
"
Actually you need to work with fputs() like below:-
<?php
$file= fopen("./test.csv","x+");
$proj_lists=explode(',',"name,age,address,city name,country name");
fputs($file,implode($proj_lists, ','));
fclose($file);
?>
Output:- name,age,address,city name,country name
I am trying to put a column with a number with leading zeros into a csv file, but it keeps truncating the leading zeros, what can I do to keep them?
Here is the code I am using:
// fopen() here
function clean_zip($string){
if(preg_match("/^\d{5,}/", $string)){
$string = str_pad($string, 5, "0", STR_PAD_LEFT);
}
return $string;
}
while(($csv = fgetcsv($rhandle)) !== false){
// other rows here
$fcsv[9] = (string)clean_zip($csv[9]);
fputcsv($whandle, $fcsv);
}
As already pointed out in the comments, wrapping a number with double quotes (") will result in something like "0123".
The way to go is adding a leading single quote (') as written down in the documentation:
If you decide to enter a number directly as text, enter an apostrophe
(') first. For example, for years in column headings, you can enter
'1999, '2000 and '2001. The apostrophe is not visible in the cell, it
only indicates that the entry is to be recognized as a text. This is
useful if, for example, you enter a telephone number or postal code
that begins with a zero (0), because a zero (0) at the start of a
sequence of digits is removed in normal number formats.
Source: Formatting Numbers as Text
The data is now parsed as a string, which results in it being ignored in a function.
Another way is to format the column as a text column.
I just needed to tell Libre Office to display the column as a Text column instead of What ever it thought would be best for the column/cell.
Wrap with double quote characters ("). This is easy enough if you're sure there are only numbers -- if there's a possibility of having quotes in the string you'll have to be more careful.
If I have a string $myString = "apple, banana, cherry"
and I want to get this data into an array, then I have two options.
$myArray = explode(", ", $myString)
or
$myArray = str_getcsv($myString)
both give the same result.
Can anybody explain the advantage/disadvantage of using one of these methods over the other?
I've heard that str_getcsv is better, according to the php manual "because explode() would not treat possible enclosured parts of string or escaped characters correctly."
Can anybody please explain what this means with the aid of a simple example?
Thanks
str_getcsv works on CSV such as:
"column 1", "column 2", and the third part
123, 567, 89
It unwraps all quoted parts, and strips the spaces from either end.
Now your simplistic explode would also do the space trimming. But it would fail / be less reliable if there is some variance in it:
1,2,3, 4, 5, 6, 7
If you are certain that there's always one comma and one space after each bit, then explode(", " would suffice. But str_getcsv is a bit more clever. It also allows to have the delimiter in quotes, as the manual hint alludes to:
"column 1 contains a , comma", "col 2 starts here"
Where the simple explode would be unaware of the special treatment for the contained comma and space.
I have a string:
A12B34C10G34LongerLongerEven LongerA57
Is there any way to separate the above using regular expressions to the form of:
A12,B34,C10,G34,Longer,Longer,Even Longer,A57
So, separated by commas. I would be grateful for any help. Thanks.
This gives what you need:
<?php
$str = "A12B34C10G34LongerLongerEven LongerA57";
echo preg_replace('/([^\s])([A-Z])/', '\1,\2', $str), "\n";
// OUTPUT: A12,B34,C10,G34,Longer,Longer,Even Longer,A57
preg_replace ('/\B([A-Z])/',',$1',$string);
Inserts a comma before any capital letter that is not on a word boundary.
My assumption is that the input data can consist of capital letters followed by numbers and capitalized words that may or may not be separated by spaces.
import re
ss = ' \tA12B34C10#G34LongerVery LongerEven LongerA57 \n'
print '%r\n%r\n\n%r' %\
(
#good 1
re.sub('(?<=\S)(?=[A-Z])', ',', ss),
#good 2
','.join(
re.findall('(\s*[A-Z].+?\s*)(?=(?<=\S)[A-Z]|\s*\Z)',ss)
),
#bad (written at first)
','.join(
re.findall('(?<!\s)([A-Z].+?)(?<!\s)(?![^A-Z])',ss)
)
)
result
' \tA12,B34,C10#,G34,Longer,Very Longer,Even Longer,A57 \n'
' \tA12,B34,C10#,G34,Longer,Very Longer,Even Longer,A57 \n'
'B34,C10#,G34,Longer,Very Longer,Even Longer'
.
The first solution is as close to the idea (inserting a comma) as possible.
(?<=\S) is mandatory in this solution because each comma must be inserted between characters (correction from DJV)
(?<!\s) would match the beginning of string and a comma would be prepended at the very first position.
.
In a first writing, I had written second solution as
# bad
','.join(re.findall( '(?<!\s)([A-Z].+?)(?<!\s)(?![^A-Z])', ss) )
or
# bad
``','.join(re.findall( '(?<!\s)([A-Z].+?)(?<!\s)(?=[A-Z]|\Z)', ss) )``
where
(?![^A-Z]) or (?=[A-Z]|\Z) were to take account of the end of the string as a possible end of matching portion.
Then
I realized that if whitespaces are at the beginning or the end of the string, there are problems. The above code shows which ones.
To prevent these problems, the solution is the good solution number 2. But it's a complicated one harder to get, so the good solution number 1 is evidently my prefered one.
Try this :
$in = 'A12B34C10G34LongerLongerEven LongerA57';
$output = trim(preg_replace('/([^\s])([A-Z])/', "$1,$2", $in),",");
echo $output;
output : A12,B34,C10,G34,Longer,Longer,Even Longer,A57
Assuming you want to add a ',' in front of each upper case character that is not preceded by a space, here is simple Python regex + sub way of doing it.
string = 'A12B34C10G34LongerLongerEven LongerA57'
re.sub(r'(?<=[^ ])([A-Z])', lambda x: ',' + x.group(0), string)
outputs:
'A12,B34,C10,G34,Longer,Longer,Even Longer,A57'
The regex makes a lookbehind to check for a non-space and the match is an upper character. Then this upper char is prepended a ','.
You could use this assuming you won't get a comma anywhere in $in
explode(",", preg_replace('/([^\s])([A-Z]+)/', "$1,$2", $in);
I don't really know python, but the base regex is the same.
I'm reading a .csv file (I have no control of the format of the file) and I'm trying to keep the leading zeros for the data in the resulting array. For instance, the .csv file has "0615" in a field, but resulting array contains "615". There are also fields in the .csv file that do not contain leading zeros, so adding zeros to the beginning of each field will not work.
I've tried to force functions to read the fields as a string, but explode, str_getcsv, fgetcsv all parse it as an integer and remove the leading zero beforehand. Any thoughts?
Edit: explode does NOT remove the leading zeros. Using explode with fgets works.
explode() works on a string basis; your type conversion must be happening elsewhere:
$data = "00555,00666,00777,00888";
$a = explode(",",$data);
foreach($a as $b) echo $b . " "; // 00555 00666 00777 00888
Use (string)$b if PHP insists on interpreting the strings as integers.
If you need the leading zeroes for presentation or uniform formatting processes then it might be easier to simply pad the numbers when you output them.
http://php.net/manual/en/function.str-pad.php should be of help here.
Use str_pad to add the leading zeros to the parsed integer, wherever you need it.
Or use sprintf, if you are familiar with it.
$num = 1;
$num = sprintf('%04d', $num);
// ^^
// ||_ How many leading digits?
// |_ Leading digit?
// output: 0001