I'm trying to look for a degree character in uploaded csv's before they are hitting my output method. As I'm writing how I would normally do this I feel like my solution will involve way more steps than it should. So, **I'm asking is there a better way to look for a ° symbol in a csv file and replace it with °. Here's what the approach I'm currently taking:
$file = get_attached_file( $csv_file ); //set file_path
$file_array = array(); //declare an array so it gets key and values approriately
$array_key = 'angle'; //define where the degree symbol is to be added
$file_array = str_getcsv(file_get_contents($file));
if( array_key_exists($array_key, $file_array) ) {
foreach ($file_array as $key => $value) {
$degree = '°';
$replace = '°';
$value = str_replace($degree, $replace, $value);
}
}
My problem is, wouldn't I then have to loop through each value in the array, put it back in a csv which would then require me to define what columns need to be outputted when some files won't have the angle column I'm trying to replace in the first place.
Also, will php be able to find and decode the ° symbol.
If replacing the degree symbol is the only thing which concerns you then this is going to be more efficient from a micro-optimization standpoint because you can skip calling the foreach(){} loop and only need to call str_replace() one time:
$file_array = str_getcsv(str_replace('°', '°', file_get_contents($file)));
Update per the comments:
// Read the CSV file into a PHP variable as a string
// Replace all ° with °
// Overwrite the original file with the new string
file_put_contents($file, str_replace('°', '°', file_get_contents($file)));
Related
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!
I have a text file that contains a persons surname, address, time of accident and reason of accident separated by a white space in a line. I need to filter this file by only the people that have called in at least two times for the same reason and echo it.
I'm fairly new to PHP so I would like a simple way. :)
Thank you.
EDIT:
I haven't tried anything since I have no clue how to even filter file contents.
$data = array($_POST['surname'], $_POST['address'], $_POST['time'], $_POST['reason']);
$info = implode(" ", $data)
$info .= "\r\n";
serialize($info);
file_put_contents("data.txt", $info, FILE_APPEND);
serialize($info);
This is how I wrote it into a file.
I imploded the file because I needed to make them separated by 3 white spaces, but it no longer matters so I can just keep the array.
The expected output should be something like this:
Surname Address Time Reason
Adams Railroad 5 13:20 Heart Attack
Adams Railroad 5 23:35 Heart Attack
It would only need to repeat the same people that have matching Surnames and Reasons.
Update
your text file contains string, entries seprated by line brakes and values by three spaces (actually html coded spaces).
Here we read whole txt file in,(some could do this line by line):
$whole_string = file_get_contents('data.txt');
So firstly we get each line:
$entries = explode('\n',$whole_string);
Then value arrays are pushed:
$whole_ar = array();
foreach($entries as $e){
$whole_ar[] = explode(' ',$e);
}//if 3 spaces in file are in html
We get:
array(
array(
'name','date','etc..'
),
array(
'name2','date','etc..'
),
array(
'name2','date','etc..'
)
)
You could store array in php file, for later to include('data.php'); like so:
$file = '<?php $whole_ar='.var_export($whole_ar, TRUE)."; ?>";
file_put_contents('data.php', $file);
Main answer on how to parse this array to target copies is iteritating or:
$answer = array_unique(array_diff_assoc($whole_ar, array_unique( $whole_ar)));
As I understand, you get information like this string when user calls in:
$newest = "Huchinson Estonia Tallin Geo street 13 2015.12.02 13:44 Gas leak"
You have this string in variable, like stated above.
Then you could explode string by space characters: $data = explode(" ",$newest); which gives you an array with number of values. First value will be a surname and last will be reason of accident.
Parse them out of array like this: echo $data[0];//this will be surname and echo end($data);//this will be accident type
Instead of echo you can assign these values to variables and look up if this surname AND accident is present in your database:
if($saved_before == $data[0].end($data)){
echo "we are working on ".end($data).", be patient, dear ".$data[0];
}
p.s. dot (.) is for concatenating strings
If i understand well the txt file is a csv file that uses a space as the delimenter of the columns. So use use fgetcsv function to load columns of each row. Specify the blank space as the delimiter.
That should get you started:
function parseIt($line) { return str_getcsv($line, " "); }
$all = array_map('parseIt', file('yourfile.txt'));
$names = array();
foreach ($all as $row) {
$uniqkey = $row[0].$row[3];
if (isset($names[$uniqkey])) {
echo implode(" ",$row);
$names[$uniqkey]++;
} else {
$names[$uniqkey] = 1;
}
}
I noticed in your file writing code you use a delimiter of 3 white spaces so I used it in the example - you can set it to whatever you want in the str_getcsv(line, delimiter)
Explanation:
Lines 1,2 - file() will read the file into an array that are passed through the function parseIt() this function will parse the line and return an array of the line value.
Line 3 - The array $names will act our memory, at the end it will hold all names + reason as keys and the value will be the counter of occurrences.
Line 4... - Loops through $all checks if the key exists in $names if it does it prints the row and moves the counter otherwise sets a new key in $names and set its value to 1 (counter).
I'm localizing a website that I've built. I'm doing this by having a .lang file read and each line (syntax: key=string) is placed in a variable depending on the chosen language.
This array is then used to place the strings in the correct places.
The problem I'm having is that certain strings need to have hyperlinks in the middle of them for example someplace I've put my name that links to my contact page. Or a lot of the readouts of the website need to be in the strings.
To solve this I've defined a variable that holds the html + Forecaster + html,
and the localization file contains the $Forecaster variable in the string.
The problem with this as I promptly discovered is that it stubbornly refuses to parse the inline variables in the strings from the file.
Instead it prints the string and variable name as it looks in the file.
And I have yet to find a way to make it parse the variables.
For example "Heating up took $str_time" would be printed on the page exactly like that, instead of inputting the previously defined value of $str_time.
I currently use fopen() and fgets() to open and read the lines. I then explode them to separate the key and the string and then place these into the array.
Is there a way to make it parse the variables, or alternatively is there another way of reading the lines that allows for parsing the inline variables?
The code that gets the line and converts it to the array looks like this:
(It obviously loops through the lines)
#list($key, $string) = explode('=', $line);
$key = strtok($line, '=');
$string = strtok('=');
$local[$key] = $string;
$counter++;
echo $local[$key] . "<br>";
The counter is unused and the echo is for testing.
A line from the .lang file looks like this:
fuel.results.heatup.timeused=Heating up took $str_time
I would call the array where I want the string like this:
$local['fuel.results.heatup.timeused']
As you can see I've tried both explode and strtok but it hasn't made a difference.
Personally I'd write your text file in JSON format to make it easier to pull data out.
Here is a solution directly from the php manual: http://nz2.php.net/manual/en/function.eval.php
$string = 'cup';
$name = 'coffee';
$str = 'This is a $string with my $name in it.';
echo $str. "\n";
eval("\$str = \"$str\";");
echo $str. "\n";
It is worth noting that eval() can be very dangerous used in the wrong way so make sure you're code is very secure E.g. if someone altered your txt file with real PHP code they could execute it directly on the server.
Another approach would require you to know all your variable names and could then do something like:
$str = 'Heating up took $str_time';
echo 'str=' . str_replace('$str_time', $str_time, $str);
Or do this via an array:
$str = 'Heating up took $str_time as well as $other_value';
$vars = Array('str_time', 'other_value');
foreach($vars as $varName) {
$str = str_replace('$' . $varName, $$varName, $str);
}
echo 'str=' . $str;
If you not know all the variable name, you can use this example, without eval(). It is indicatred to avoid eval().
$str = 'fuel.results.heatup.timeused=Heating up took $str_time';
$str_time = 'value';
if(preg_match('/\$([a-z0-9_]+)/i', $str, $v)) {
$vname = $v[1];
$str = str_replace('$'.$vname, $$vname, $str);
}
echo $str; // fuel.results.heatup.timeused=Heating up took value
Hacking up what I thought was the second simplest type of regex (extract a matching string from some strings, and use it) in php, but regex grouping seems to be tripping me up.
Objective
take a ls of files, output the commands to format/copy the files to have the correct naming format.
Resize copies of the files to create thumbnails. (not even dealing with that step yet)
Failure
My code fails at the regex step, because although I just want to filter out everything except a single regex group, when I get the results, it's always returning the group that I want -and- the group before it, even though I in no way requested the first backtrace group.
Here is a fully functioning, runnable version of the code on the online ide:
http://ideone.com/2RiqN
And here is the code (with a cut down initial dataset, although I don't expect that to matter at all):
<?php
// Long list of image names.
$file_data = <<<HEREDOC
07184_A.jpg
Adrian-Chelsea-C08752_A.jpg
Air-Adams-Cap-Toe-Oxford-C09167_A.jpg
Air-Adams-Split-Toe-Oxford-C09161_A.jpg
Air-Adams-Venetian-C09165_A.jpg
Air-Aiden-Casual-Camp-Moc-C09347_A.jpg
C05820_A.jpg
C06588_A.jpg
Air-Aiden-Classic-Bit-C09007_A.jpg
Work-Moc-Toe-Boot-C09095_A.jpg
HEREDOC;
if($file_data){
$files = preg_split("/[\s,]+/", $file_data);
// Split up the files based on the newlines.
}
$rename_candidates = array();
$i = 0;
foreach($files as $file){
$string = $file;
$pattern = '#(\w)(\d+)_A\.jpg$#i';
// Use the second regex group for the results.
$replacement = '$2';
// This should return only group 2 (any number of digits), but instead group 1 is somehow always in there.
$new_file_part = preg_replace($pattern, $replacement, $string);
// Example good end result: <img src="images/ch/ch-07184fs.jpg" width="350" border="0">
// Save the rename results for further processing later.
$rename_candidates[$i]=array('file'=>$file, 'new_file'=>$new_file_part);
// Rename the images into a standard format.
echo "cp ".$file." ./ch/ch-".$new_file_part."fs.jpg;";
// Echo out some commands for later.
echo "<br>";
$i++;
if($i>10){break;} // Just deal with the first 10 for now.
}
?>
Intended result for the regex: 788750
Intended result for the code output (multiple lines of): cp air-something-something-C485850_A.jpg ./ch/ch-485850.jpg;
What's wrong with my regex? Suggestions for simpler matching code would be appreciated as well.
Just a guess:
$pattern = '#^.*?(\w)(\d+)_A\.jpg$#i';
This includes the whole filename in the match. Otherwise preg_replace() will really only substitute the end of each string - it only applies the $replacement expression on the part that was actually matched.
Scan Dir and Expode
You know what? A simpler way to do it in php is to use scandir and explode combo
$dir = scandir('/path/to/directory');
foreach($dir as $file)
{
$ext = pathinfo($file,PATHINFO_EXTENSION);
if($ext!='jpg') continue;
$a = explode('-',$file); //grab the end of the string after the -
$newfilename = end($a); //if there is no dash just take the whole string
$newlocation = './ch/ch-'.str_replace(array('C','_A'),'', basename($newfilename,'.jpg')).'fs.jpg';
echo "#copy($file, $newlocation)\n";
}
#and you are done :)
explode: basically a filename like blah-2.jpg is turned into a an array('blah','2.jpg); and then taking the end() of that gets the last element. It's the same almost as array_pop();
Working Example
Here's my ideaone code http://ideone.com/gLSxA
My script lists out files in the directory. I am able to use preg_match and regex to find files whose filenames contain integers.
However, this is what I am unable to do: I want an entire string to be omitted if it contains an integer.
Despite trying several methods, I am only able to replace the integer itself and not the entire line. Any help would be appreciated.
if (preg_match('/\d/', $string))
$string = "";
This will turn a string into an empty one if it has any number in it.
According to your description, this should be sth. like:
$files = array();
$dirname = 'C://Temp';
$dh = opendir($dirname) or die();
while( ($fn=readdir($dh)) !== false )
if( !preg_match('/\d+|^\.\.?$/', $fn) )
$files[] = $fn;
closedir($dh);
var_dump($files);
... which reads all file names and stores them (except these with numbers and ../.) in an array '$files', which itself gets displayed at the end of the snipped above. If that doesn't fit your requirement, you should give a more detailed explanation of what you are trying to do
Regards
rbo