I have the following street names and house numbers in a text file:
Albert Dr: 4116-4230, 4510, 4513-4516
Bergundy Pl: 1300, 1340-1450
David Ln: 3400, 4918, 4928, 4825
Garfield Av: 5000, 5002, 5004, 5006, 8619-8627, 9104-9113
....
This data represents the boundary data for a local neighborhood (i.e., what houses are inside the community).
I want to make a PHP script that will take a user's input (in the form of something like "4918 David Lane" or "3000 Bergundy") search this list, and return a yes/no response whether that house exists within the boundaries.
What would be an efficient way to parse the input (regex?) and compare it to the text list?
Thanks for the help!
It's better to store this info in a database so that you don't have to parse out the data from a text file. Regexes are also not generally applicable to find a number in a range so a general purpose language is advised as well.
But... if you want to do it with regexes (and see why it's not a good idea)
To lookup the numbers for a street use
David Ln:(.*)
To then get the numbers use
[^,]*
You could simply import the file into a string. After this is done, breack each line of the file in an array so Array(Line 1=> array(), Line 2=> array(), etc. After this is done, you can explode using :. After, you'll simply need to search in the array. Not the fastest way, but it may be faster then regex.
You should sincerely consider using a database or re-think how your file are.
Try something like this, put your street names inside test.txt.. Now that you are able to get the details inside the text file, just compare it with the values that you submit in your form.
$filename = 'test.txt';
if(file_exists($filename)) {
if($handle = fopen($filename, 'r')) {
$name = array();
while(($file = fgets($handle)) !==FALSE) {
preg_match('#(.*):(.*)#', $file, $match);
$array = explode(',', $match[2]);
foreach($array as $val) {
$name[$match[1]][] = $val;
}
}
}
}
As mentioned, using a database to store street numbers that are relational to your street names would be ideal. I think a way you could implement this with your text file though is to create a a 2D array; storing the street names in the first array and the valid street numbers in their respective arrays.
Parse the file line by line in a loop. Parse the street name and store in array, then use a nested loop to parse all of the numbers (for ones in a range like 1414-1420, you can use an additional loop to get each number in the range) and build the next array in the initial street name array element. When you have your 2D array, you can do a simple nested loop to check it for a match.
I will try to make a little pseudo-code for you..
pseudocode:
$addresses = array();
$counter = 0;
$line = file->readline
while(!file->eof)
{
$addresses[$counter] = parse_street_name($line);
$numbers_array = parse_street_numbers($line);
foreach($numbers_array as $num)
$addresses[$counter][] = $num;
$line = file->readline
$counter++;
}
It's better if you store your streets in a separate table with IDs, and store numbers in separate table one row for each range or number and street id.
For example:
streets:
ID, street
-----------
1, Albert Dr
2, Bergundy Pl
3, David Ln
4, Garfield Av
...
houses:
street_id, house_min, house_max
-----------------
1, 4116, 4230
1, 4510, 4510
1, 4513, 4516
2, 1300, 1300
2, 1340, 1450
...
In the rows, where no range but one house number, you set both min and max to the same value.
You can write a script, that will parse your txt file and save all data to db. That should be as easy as several loops and explode() with different parameters and some insert queries too.
Then with first query you get street id
SELECT id FROM streets WHERE street LIKE '%[street name]%'
After that you run second query and get answer, is there such house number on that street
SELECT COUNT(*)
FROM houses
WHERE street_id = [street_id]
AND [house_num] BETWEEN house_min AND house_max
Inside [...] you put real values, dont forget to escape them to prevent sql injections...
Or you even can run just one query using JOIN.
Also you should make sure that your given house number is integer, not float.
Related
file_name = 'Delta_SLAs.csv';
fileID = fopen(file_name, 'wt');
A = {'HRC-ID', '45700037'};
B = {'HRC-ID', '45700038'};
C = {'HRC-ID', '45700017'};
D = {'HRC-ID', '45700018'};
fprintf(fileID, '%s,', A{1,1:end});
fprintf(fileID, '\n%s,', txt{1,7}{14:end,1});
csvwrite(file_name, deltas_37, 1, 2);
fclose(fileID)
*txt is the vertical text array
*deltas_37 is the numeric vertical array
writing in the string array works nicely but when I try to write the numeric array it writes over the previous data.
The task is to write the txt array and then write the numeric array in the column next to it to reference.
Same is to be done for next 3 sets of data which is meant to be written right below the previous data set
I feel like I am missing some little manipulation and it will all work. If anyone can guide to the right direction it would be awesome.
Thank you
csvwrite will always overwrite the file, but you can use dlmwrite instead:
dlmwrite(file_name, deltas_37, 'delimiter', ',', 'roffset', 1, 'coffset', 2, '-append');
As you can see below, I'm attempting to extract the complete substring of an exploded array by using just a few characters to match the substring.
$keyword = array('Four Wheel', 'Power', 'Trailer');
function customSearch($keyword, $featurelistarray){
$key = ''; //possibly reset output
foreach($featurelistarray as $key => $arrayItem){
if( stristr( $arrayItem, $keyword ) ){
$termname = $key;
}
}
}
The array ($featurelistarray) comprises vehicle options, four wheel drive, four wheel disc brakes, power windows, power door locks, floor mats, trailer tow package, and many many more.
The point is to list all the options for a given category, and using the $keyword array to define the category.
I would also like to alphabetize the results. Thank you for the help!
To further explain, the $featurelistarray is exploded from a CSV field. The CSV field has a long length of options listed.
$featurelist=$csvdata['Options'];
$featurelistarray=explode(',',$featurelist);
$termname = $featurelistarray[0];
As you can see, $termname is assigned the first position of the exploded array. This was the original code for these features, but I need more control for $termname.
It seems to me you are trying to make database operations without database. I'd suggest to transform input into some kind of database.
Hello I am trying to pull back roster information from ESPN.com. Each team's roster is saved into a table. I am trying to figure a way to save each tag into a variable as appropriate however each tag does not have an ID such as "jersey_number"/"player_name" so search through this has given me some problems. Here is what I have so far - If you could give me a pointer or 2 that would be much appreciated.
<?php
require_once("../tools/simple_html_dom.php");
require_once("../tools/Utilities.php");
$url = "http://espn.go.com/nfl/team/roster/_/name/den/denver-broncos";
$espnHTML = file_get_html("http://espn.go.com/nfl/team/roster/_/name/den/denver-broncos");
foreach($espnHTML->find("table.tablehead",0)->find('tr[class^=odd]') as $rosterRow)
{
foreach($rosterRow->find("td") as $playerInfo)
{
echo $playerInfo->plaintext."<br>";
}
}
?>
How can I assign these td tags into appropriate variables without "ids"? Attached is a sample screenshot that may help you understand what I am talking about.
If the columns are in the same order for every player, using your $rosterrow->find("td") should return an indexed array that you can access using $playerrow[0..n].
Then, by analyzing what corresponds to what you can make a function like this:
$players = array();
foreach($espnHTML->find("table.tablehead",0)->find('tr[class^=odd]') as $rosterRow)
{
$playerRow = $rosterRow->find("td");
$name = $playerRow[0];
$jersey = $playerRow[1];
// more can be added, of course.
$players[$name] = array();
$players[$name]["jersey"] = $jersey;
// and others
}
For table
John Appleseed | 12
---------------|----
Richard Brooks | 34
this will result in an array like
{ "John Appleseed" => { "jersey" => 12 }, "Richard Brooks" => { "jersey" => 34}}
Please let me know if this helped.
If you're open to a different approach that may be more scalable/robust, then you may also want to take a look at Kimono Labs. You can use it to create structured API based on ESPN's data. I think you'd be able to define which part of the table held names, scores, etc. and would easily be able to call the API for the desired info.
Below is a link to my original question:
PHP: How to display a variable (a) within another variable(b) when variable (b) contains text
Ok here's more to the problem, all your suggestions work but now I'm looking for the most efficient method to my specific problem.
In my database I have several blocks of text. When a user(described as $teamName) logs in to the site, they are randomly assigned one of these blocks of text. Each block of text is different and may have different variables in it.
The problem is I don't have knowledge of which block of text is assigned to the user without actually viewing the database or running a query. So at the moment I have to query the database and select the $newsID that corresponds to the block of text that the user has been assigned.
Because I have preset the blocks of text, I know what they contain so I can know do a switch($newsID) and depending on the value of the $newsID I then run the correct values inserted into the sprintf() function.
There is however, many many blocks of text so there will be many instances of case "": and break;. I wish to have the site working so that if at any stage I change a block of text to something different, then the variables within sprintf() are automatically updated, rather than me manually updating sprintf() within the switch() case:.
Sorry for the long post, hope it makes sense.
EDIT:
I have these predetermined blocks of text in my database in my teamNews table:
For $newsID = 1:
"$teamName is the name of a recently formed company hoping to take over the lucrative hairdryer design
$sector"
For $newsID = 2:
"The government is excited about the potential of ".$teamName.", after they made an annoucement that they have hired $HoM"
For $newsID = 3:
"It is rumored that $teamName are valuing their hairdryer at $salePrice. People are getting excited.
When a user($teamName) logs into the game they are randomly assigned one of these blocks of text with $newsID of 1,2 or 3.
Lets say the user is assigned the block of text with $newsID = 2. So now their username($teamName) is inserted into the database into the same row as their selected text.
Now I want to display the text corresponding to this user so I do the following:
$news = news ($currentStage,$teamName);
switch ($ID)
{
case "1":
sprintf($teamName,$sector)
echo $news."<br/><hr/>";
break;
case "2":
sprintf($teamName,$Hom)
break;
case "3":
sprintf($teamName,$saleprice)
break;
}
$currentStage--;
}
With the function
function news($period,$teamName)
{
$news = mysql_query("
SELECT `content`,`newsID` FROM `teamnews` WHERE `period` = '$period' && `teamName` = '$teamName'
") or die($news."<br/><br/>".mysql_error());
$row = mysql_fetch_assoc($news);
$news = $row['content'];
$ID = $row ['newsID'];
return $news,$ID;
}
The problem is that in reality there are about 20 different blocks of text that the user could be assigned to. So I will have many case:'s.
Also if I want to change all the text blocks in the database I would have to also manually change all the variables in the sprintf's in each ``case:`
I am wondering is there a better way to do this so that if I change the text in the database then the paramaters passed to sprintf will change accordingly.
So if I use
$replaces = array(
'teamName' => 'Bob the team',
'sector' => 'murdering',
'anotherSector' => 'giving fluffy bunnies to children'
);
is it possible to do this:
$replaces = array(
'$teamName' => '$teamName',
'$sector' => '$sector',
'$anotherSector' => '$anothersector'
);
I suggest you have fixed set of named placeholders, and use either the str_replace() or eval() (evil) methods of substitution.
So you would (for example) always have a $teamName and a $sector - and you might only sometimes use $anotherSector. And you have these two strings:
1 - $teamName, is the name of a recently formed company hoping to take over the lucrative $sector.
2 - The people at $teamName hate working in $sector, they would much rather work in $anotherSector
If you were to do:
$replaces = array(
'$teamName' => 'Bob the team',
'$sector' => 'murdering',
'$anotherSector' => 'giving fluffy bunnies to children'
);
$news = str_replace(array_keys($replaces),array_values($replaces),$news);
You would get
1 - Bob the team, is the name of a recently formed company hoping to take over the lucrative murdering.
2 - The people at Bob the team hate working in murdering, they would much rather work in giving fluffy bunnies to children
As long as your placeholders have known names, they don't all have to be present in the string - only the relevant ones will be replaced.
You could create a simple template language, and store templates in your database.
You can use strtr for this.
function replaceTemplateVars($str, $data) {
// change the key format to correspond to the template replacement format
$replacepairs = array();
foreach($data as $key => $value) {
$replacepairs["{{{$key}}}"] = $value;
}
// do the replacement in bulk
return strtr($str, $replacepairs);
}
// store your teamNews table text in this format
// double curly braces is easier to spot and less ambiguous to parse than `$name`.
$exampletemplate = '{{teamName}} is {{sector}} the {{otherteam}}!!'
// get $values out of your database for the user
$values = array(
'teamName' => 'Bob the team',
'sector' => 'murdering',
'otherteam' => 'fluffy bunnies'
);
echo replaceTemplateVars($exampletemplate, $values);
// this will echo "Bob the team is murdering the fluffy bunnies!!"
If you have needs more ambitious than this, such as looping or filters, you should find a third-party php template language and use it.
What about function eval?
http://php.net/eval
I have a text file with something like
Country1
city1
city2
Country2
city3
city4
I want to separate country and cities. Is there any quick way of doing it? I am thinking of some file handling and then extracting to different files, is it best way or can be done with some regex etc quickly?
countries=[]
cities=[]
with open("countries.txt") as f:
gap=True
for line in f:
line=line.strip()
if gap:
countries.append(line)
gap=False
elif line=="":
gap=True
else:
cities.append(line)
print countries
print cities
output:
['Country1', 'Country2']
['city1', 'city2', 'city3', 'city4']
if you want to write these to files:
with open("countries.txt","w") as country_file, open("cities.txt","w") as city_file:
country_file.write("\n".join(countries))
city_file.write("\n".join(cities))
f = open('b.txt', 'r')
status = True
country = []
city = []
for line in f:
line = line.strip('\n').strip()
if line:
if status:
country.append(line)
status = False
else:
city.append(line)
else:
status = True
print country
print city
output :
>>['city1', 'city2', 'city3', 'city4']
>>['Country1', 'Country2']
$countries = array();
$cities = array();
$gap = false;
$file = file('path/to/file');
foreach($file as $line)
{
if($line == '') $gap = true;
elseif ($line != '' and $gap)
{
$countries[] = $line;
$gap = false;
}
elseif ($line != '' and !$gap) $cities[] = $line;
}
Depending on how regular your file is, it may be this simple in python:
with open('inputfile.txt') as fh:
# To iterate over the entire file.
for country in fh:
cityLines = [next(fh) for _i in range(2)]
# read a blank line to advance countries.
next(fh)
That's not likely to be exactly right, because I imagine many countries have variable numbers of cities. You could modify it like so to address that:
with open('inputfile.txt') as fh:
# To iterate over the entire file.
for country in fh:
# we assume here that each country has at least 1 city.
cities = [next(fh).strip()]
while cities[-1]: # will continue until we encounter a blank line.
cities.append(next(fh).strip())
That doesn't do anything to put the data into an output file, or store it much past the file handle itself, but it's a start. You really should choose a language for your questions though. A lot of the time until
Another PHP example that doesn't read the entire file in an array.
<?php
$fh = fopen('countries.txt', 'r');
$countries = array();
$cities = array();
while ( $data = fgets($fh) )
{
// If $country is empty (or not defined), the this line is a country.
if ( ! isset($country) )
{
$country = trim($data);
$countries[] = $country;
}
// If an empty line is found, unset $country.
elseif ( ! trim($data) )
unset($country);
// City
else
$cities[$country][] = trim($data);
}
fclose($fh);
The $countries array will contain a list of countries while the $cities array will contain a list of cities by countries.
Is there some pattern that distinguishes countries from cities? Or is it that the first line after a blank line is a country and all subsequent lines are city names until the next blank line? Alternatively are you finding countries based on a look-up table (a "dictionary" in Python; an associative array in PHP; a hash in Perl --- one that includes all the officially recognized countries)?
Is it safe to assume that there are no cities whose names collide with any country? Is there a France, Iowa, USA, or the old Usa, Japan?
What do you want to do with these after you separate them? You mention "some file handling and then extracting to different files" --- are you thinking of something like one file per country containing a list of all the cities therein? Or one directory per country and one file per city?
The obvious approach would be to iterate over the file, line by line, and maintain a little state machine: empty (beginning of file, blank lines between countries?) during which you enter the "country" state (whenever you found any pattern that matches whatever criteria means you've encountered the name of a country). Once you've found a country name then you're in the city loading state. I would create a dictionary using country names as keys and set of cities as cities (though perhaps you might really need county/provice, city name tuples in cases where a country has multiple cities by the same name: Portland, Maine vs. Portland, Oregon, for example). You can also have some "error" state if the contents of your file lead to some sort of ambiguity (city names before you've determined a country, two country names in a row, whatever).
It's hard to suggest a good fragment of code given how vague your spec. here is.
Not sure that this would help, but you can try to use the following code to get dictionary and then work with it(write to files, compare and etc):
res = {}
with open('c:\\tst.txt') as f:
lines = f.readlines()
for i,line in enumerate(lines):
line = line.strip()
if (i == 0 and line):
key = line
res[key] = []
elif not line and i+1 < len(lines):
key = lines[i+1].strip()
res[key] = []
elif line and line != key:
res[key].append(line)
print res
This regex would work for your example:
/(?:^|\r\r)(.+?)\r(.+?)(?=\r\r|$)/s
Catches countries in group 1 and cities in group 2.
You may have to adjust your newline characters, depending on your system. They can be \n, \r or \r\n. edit: added a $ sign, so you don't need two linebreaks at the end. You will need the flag for dotall for the regex to work as expected.
Print fild 1 with awk - countries
awk 'BEGIN {RS="";FS="\n"} {print $1 > "countries"} {for (i=2;i<=NF;i++) print $i > "cities"}' source.txt