I'm currently fighting with excluding empty lines to be saved into the array $presidents (and by doing that, solving a problem where the foreach loop echoes the strings without Names).
I've tried a few things which should have worked, in my amateur opinion of course (preg_match(), trim(), etc.).
Can someone help me with this?
$file = fopen("namen2.txt", "r");
$presidents = array();
$count = count(file("namen2.txt"));
for($i = 1; $i <= $count;){
$file_line = fgets($file);
$line = explode(" ", $file_line);
$president = array();
$president["firstname"] = $line[0];
if(empty($president["firstname"] == false)){
$president["lastname"] = $line[1];
$president["counter"] = $i;
$presidents[] = $president;
$i++;
}
else{echo "fehler";}
}
foreach($presidents as $president_order){
echo "Hey ". $president_order["firstname"]. " ". $president_order["lastname"]. ", du bist der ". $president_order["counter"]. ". Präsident der USA in meiner Liste. \n";
}
Edit: I've solved my problems by changing conditions and controlling my input at the insertion phase, thanks for the great tips!
You should be dealing with spaces and unwanted characters at the insertion phase of the data, not after it so you should go back to that code and clean the data before the insertion takes place.
Using PHP's trim should work, there's no reason why it should not work for you. If you have a variable holding a string like " Firstname Lastname " then using that function will turn it to "Firstname Lastname".
It seems you are splitting each piece of data with spaces... that's not a good idea considering your data may possibly have to include spaces (First names can have spaces too, Mary Jane for example).
You can spot and delete empty lines with the following regular expression:
preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $presidents);
Since it's an array you may need to loop through array elements though.
I didn't test this code, but it seems like a tighter way to accomplish the task. Just trim() and check for positive string length. I've added an element-limit to explode() and condensed your data storage syntax.
$file=fopen("namen2.txt","r");
$i=0; // initialize counter
while(!feof($file)){
$line=trim(fgets($file)); // get line and trim leading/trailing whitespaces from it
if(strlen($line)){ // if there are any non-whitespace characters, proceed
$names=explode(' ',$line,2); // max of two elements produced, in case: Martin Van Buren
// explode will fail to correctly split: John Quincy Adams
$presidents[]=['counter'=>++$i,'firstname'=>$names[0],'lastname'=>(isset($names[1])?$names[1]:'')]; // store the data for future processing
}
}
fclose($file);
foreach($presidents as $pres){
echo "Hey {$pres["firstname"]} {$pres["lastname"]}, du bist der {$pres["counter"]} Präsident der USA in meiner Liste.\n";
}
Related
I'm working on a script that allows students to input their answers into a form and gives them instant feedback on their answers.
I start with a string ($content) that contains the complete task with the gaps in square brackets, something like this:
There's [somebody] in the room. There isn't [anybody] in the room.
Is [anybody] in the room?
Now the script recognizes the solutions (somebody, anybody, anybody) and saves them in an array. The student's answers are also in an array.
To see if the answer is correct, the script checks if $input[$i] and $solution[$i] are identical.
Now here is the problem: I want the script to replace the placeholders with an input box where the solution is wrong and the solution in green where it's correct. This updated version of $content is then shown on the next page.
But if there are two identical solutions, this results in multiple replacements as the replacement is replaced again...
I tried preg_replace with a limit of 1 but this doesn't do the trick either as it doesn't skip solutions that have already been replaced.
$i=0;
while ($solution[$i]){
//answer correct
if($solution[$i] == $input[$i]){
//replace placeholder > green solution
$content = str_replace($solution[$i], $solution_green[$i], $content);
}
//answer wrong
else{
//replace placeholder > input box to try again
$content = str_replace($solution[$i], $solution_box[$i], $content);
}
$i++;
}
print $content; //Output new form based on student's answer
Is there any way to avoid replacing replacements?
I hope I didn't ramble too much... Have been wracking my brain for ages over this problem and would appreciate any suggestions.
The way I've approached this is to split the original content into segments which relate to the markers in the text. So then you explode() the original text by ], you end up with...
Array
(
[0] => There's [somebody
[1] => in the room. There isn't [anybody
[2] => in the room.
Is [anybody
[3] => in the room?
)
As you can see, each array element now corresponds with the answer/solution numbers. So when replacing the text, it changes $parts[$i] instead. Also as a safeguard, it replaces [text to make sure, there are other solutions, but this should do the job.
At the end, the code then rebuilds the original content by using implode() and using ] to add it back.
$parts = explode("]", $content);
$i=0;
while (isset($solution[$i])){
//answer correct
if($solution[$i] == $input[$i]){
//replace placeholder > green solution
$parts[$i] = str_replace("[".$solution[$i], "[".$solution_green[$i], $parts[$i]);
}
//answer wrong
else{
//replace placeholder > input box to try again
$parts[$i] = str_replace("[".$solution[$i], "[".$solution_box[$i], $parts[$i]);
}
$i++;
}
$content = implode( "]", $parts);
You may use sprintf()/vsrpintf() function to replace positional placeholders, but first you'd have to prepare sentence pattern for it. Each "solution placeholder" should be replaced with %s, so that later sprintf() could replace each one with corresponding string.
You may do that within loop:
$fields = [];
while (isset($solution[$i])) {
$fields[] = ($solution[$i] === $input[$i])
? $solution_green[$i]
: $solution_box[$i];
//doesn't matter if you replace more than one here
$content = str_replace($solution[$i], '%s', $content);
$i++;
}
print vsprintf($content, $fields);
//or for php>=5.6: sprintf($content, ...$fields);
This is an easy-fix solution to current state of your code. It may be refactored (pattern replacement while parsing correct words, green/box arrays may be replaced with methods producing string you need... etc.)
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).
Basically what I am trying to do here is get a text input (a paragraph), and then save each word into an array. Then I want to check each word in the array against the original paragraph to see how many times it occurred. By doing this I am hopefully going to be able to check what the topic is. Originally I started this is as an open ended school project, but I am more interested in finding out how to do this for my own sanity.
Here is my code (this is after I requested the text input in html code above):
$paragraph = $_POST['text'];
$paragraph = str_replace(' ',' ',$paragraph);
$paragraph = str_replace(' ',' ',$paragraph);
$paragraph = strtolower($paragraph);
$words = explode(" ",$paragraph);
$count = count($words);
for($x = 0; $x < $count; $x++) {
echo $words[$x];
echo "<br/>";
}
So far I have been able to get the words all lowercase and to replace all the extra spaces in my text, and then subsequently save that to an array. For now I am just displaying the words.
This is where I have run into some problems. I was thinking I could have a multidimensional array where it would be something along the lines of
$words[1]["word"][0]["amount"];
The word would be the actual word in the paragraph, and amount would count how many times it showed up in the paragraph. If anyone has basic concepts for doing this, or there is something I am missing here I would appreciate your help. The main thing I need help with is checking the amount of times each word shows up in the paragraph. I couldn't get this to work (it was within the prior for loop):
substr_count($words[$x],$paragraph)
To recap, I am trying to take a paragraph, save each different word into an array (I have managed to do this successfully) and then save the amount of times the word shows up in the paragraph into a different array (or a multidimensional array). Once I get this data I am going to see which words I used the most, while filtering out filler words like "the" and "a".
You would be better off using preg_replace('/\W+/', ' ', $paragraph); and simplifying the rest of your code to this:
$paragraph = preg_replace('/\W+/', ' ', $paragraph);
$filter = array('the', 'a');
$words = explode(' ',$paragraph);
$countWords = array();
foreach($words as $w)
{
if(trim($w) != "" && array_search($w, $filter) === false)
{
if(!isset($countWords[$w]))
$countWords[$w] = 0;
$countWords[$w] += 1;
}
}
This will give you how many times each word is used. And if you don't care about case, then you can use $countWords[strtolower($w)] instead. Also, with the $filter array I added, you can add whatever words that you don't want to count in there.
I have a very big .txt file with our clients order and I need to move it in a mysql database . However I don't know what kind of regex to use as the information is not very different .
-----------------------
4046904
KKKKKKKKKKK
Laura Meyer
MassMutual Life Insurance
153 Vadnais Street
Chicopee, MA 01020
US
413-744-5452
lmeyer#massmutual.co...
KKKKKKKKKKK
373074210772222 02/12 6213 NA
-----------------------
4046907
KKKKKKKKKKK
Venkat Talladivedula
6105 West 68th Street
Tulsa, OK 74131
US
9184472611
venkat.talladivedula...
KKKKKKKKKKK
373022121440000 06/11 9344 NA
-----------------------
I tried something but I couldn't even extract the name ... here is a sample of my effort with no success
$htmlContent = file_get_contents("orders.txt");
//print_r($htmlContent);
$pattern = "/KKKKKKKKKKK(.*)\n/s";
preg_match_all($pattern, $htmlContent, $matches);
print_r($matches);
$name = $matches[1][0];
echo $name;
You may want to avoid regexes for something like this. Since the data is clearly organized by line, you could repeatedly read lines with fgets() and parse the data that way.
You could read this file with regex, but it may be quite complicated create a regex that could read all fields.
I recommend that you read this file line by line, and parse each one, detecting which kind of data it contains.
As you know exactly where your data is (i.e. which line its on) why not just get it that way?
i.e. something like
$htmlContent = file_get_contents("orders.txt");
$arrayofclients = explode("-----------------------",$htmlContent);
$newlinesep = "\r\n";
for($i = 0;i < count($arrayofclients);$i++)
{
$temp = explode($newlinesep,$arrayofclients[i]);
$idnum = $temp[0];
$name = $temp[4];
$houseandstreet = $temp[6];
//etc
}
or simply read the file line by line using fgets() - something like:
$i = 0;$j = 0;
$file = fopen("orders.txt","r");
$clients = [];
while ($line = fgets($ffile) )
{
if(line != false)
{
$i++;
switch($i)
{
case 2:
$clients[$j]["idnum"] = $line;
break;
case 6:
$clients[$j]["name"] = $line;
break;
//add more cases here for each line up to:
case 18:
$j++;
$i = 0;
break;
//there are 18 lines per client if i counted right, so increment $j and reset $i.
}
}
}
fclose ($f);
You could use regex's, but they are a bit awkward for this situation.
Nico
For the record, here is the regex that will capture the names for you. (Granted speed very well may be an issue.)
(?<=K{10}\s{2})\K[^\r\n]++(?!\s{2}-)
Explanation:
(?<=K{10}\s{2}) #Positive lookbehind for KKKKKKKKKK then 2 return/newline characters
\K[^\r\n]++ #Greedily match 1 or more non-return/newline characters
(?!\s{2}-) #Negative lookahead for return/newline character then dash
Here is a Regex Demo.
You will notice that my regex pattern changes slightly between the Regex Demo and my PHP Demo. Slight tweaking depending on environment may be required to match the return / newline characters.
Here is the php implementation (Demo):
if(preg_match_all("/(?<=K{10}\s{2})\K[^\r\n]++(?!\s{2}-)/",$htmlContent,$matches)){
var_export($matches[0]);
}else{
echo "no matches";
}
By using \K in my pattern I avoid actually having to capture with parentheses. This cuts down array size by 50% and is a useful trick for many projects. The \K basically says "start the fullstring match from this point", so the matches go in the first subarray (fullstrings, key=0) of $matches instead of generating a fullstring match in 0 and the capture in 1.
Output:
array (
0 => 'Laura Meyer',
1 => 'Venkat Talladivedula',
)
My new phone does not recognize a phone number unless its area code matches the incoming call. Since I live in Idaho where an area code is not needed for in-state calls, many of my contacts were saved without an area code. Since I have thousands of contacts stored in my phone, it would not be practical to manually update them. I decided to write the following PHP script to handle the problem. It seems to work well, except that I'm finding duplicate area codes at the beginning of random contacts.
<?php
//the script can take a while to complete
set_time_limit(200);
function validate_area_code($number) {
//digits are taken one by one out of $number, and insert in to $numString
$numString = "";
for ($i = 0; $i < strlen($number); $i++) {
$curr = substr($number,$i,1);
//only copy from $number to $numString when the character is numeric
if (is_numeric($curr)) {
$numString = $numString . $curr;
}
}
//add area code "208" to the beginning of any phone number of length 7
if (strlen($numString) == 7) {
return "208" . $numString;
//remove country code (none of the contacts are outside the U.S.)
} else if (strlen($numString) == 11) {
return preg_replace("/^1/","",$numString);
} else {
return $numString;
}
}
//matches any phone number in the csv
$pattern = "/((1? ?\(?[2-9]\d\d\)? *)? ?\d\d\d-?\d\d\d\d)/";
$csv = file_get_contents("contacts2.CSV");
preg_match_all($pattern,$csv,$matches);
foreach ($matches[0] as $key1 => $value) {
/*create a pattern that matches the specific phone number by adding slashes before possible special characters*/
$pattern = preg_replace("/\(|\)|\-/","\\\\$0",$value);
//create the replacement phone number
$replacement = validate_area_code($value);
//add delimeters
$pattern = "/" . $pattern . "/";
$csv = preg_replace($pattern,$replacement,$csv);
}
echo $csv;
?>
Is there a better approach to modifying the CSV? Also, is there a way to minimize the number of passes over the CSV? In the script above, preg_replace is called thousands of times on a very large String.
If I understand you correctly, you just need to prepend the area code to any 7-digit phone number anywhere in this file, right? I have no idea what kind of system you're on, but if you have some decent tools, here are a couple options. And of course, the approaches they take can presumably be implemented in PHP; that's just not one of my languages.
So, how about a sed one-liner? Just look for 7-digit phone numbers, bounded by either beginning of line or comma on the left, and comma or end of line on the right.
sed -r 's/(^|,)([0-9]{3}-[0-9]{4})(,|$)/\1208-\2\3/g' contacts.csv
Or if you want to only apply it to certain fields, perl (or awk) would be easier. Suppose it's the second field:
perl -F, -ane '$"=","; $F[1]=~s/^[0-9]{3}-[0-9]{4}$/208-$&/; print "#F";' contacts.csv
The -F, indicates the field separator, the $" is the output field separator (yes, it gets assigned once per loop, oh well), the arrays are zero-indexed so second field is $F[1], there's a run-of-the-mill substitution, and you print the results.
Ah programs... sometimes a 10-min hack is better.
If it were me... I'd import the CSV into Excel, sort it by something - maybe the length of the phone number or something. Make a new col for the fixed phone number. When you have a group of similarly-fouled numbers, make a formula to fix. Same for the next group. Should be pretty quick, no? Then export to .csv again, omitting the bad col.
A little more digging on my own revealed the issues with the regex in my question. The problem is with duplicate contacts in the csv.
Example:
(208) 555-5555, 555-5555
After the first pass becomes:
2085555555, 208555555
and After the second pass becomes
2082085555555, 2082085555555
I worked around this by changing the replacement regex to:
//add escapes for special characters
$pattern = preg_replace("/\(|\)|\-|\./","\\\\$0",$value);
//add delimiters, and optional area code
$pattern = "/(\(?[0-9]{3}\)?)? ?" . $pattern . "/";