Adding links to a PHP array list? - php

I never intended to have to use PHP - heck, two days ago I didn't even know what it was, so excuse me if any of my terminology is weird or incorrect.
My predicament is that I need a working code that will end up outputting a list of writer names (that's why the array is called "writers") that are linked to their writer pages/profiles. Here's what I have so far that correctly displays the list of writer names:
<?php
$writers = get_post_meta($post->ID, 'writer', false);
$last = array_slice($writers, -1);
$first = join(', ', array_slice($writers, 0, -1));
$both = array_filter(array_merge(array($writers), $last), 'strlen');
echo join(' and ', $both);
?>
And the correct writer page link can be generated with this code:
<?php echo get_post_meta($post->ID, 'writerlink', true); ?>
I just don't have the skill to get these puzzle pieces to fit together. Since there are often multiple writers, there will often be more than one writer link. Is it possible to have each list/array value to have its correct link attached?

Related

Parsing a mixed-delimiter data set

I've got a source file that contains some data in a few formats that I need to parse. I'm writing an ETL process that will have to match other data.
Most of the data is in the format city, state (US standard, more or less). Some cities are grouped across heavier population areas with multiple cities combined.
Most of the data looks like this (call this 1):
Elkhart, IN
Some places have multiple cities, delimited by a dash (call this 2):
Hickory-Lenoir-Morganton, NC
It's still not too complicated when the cities are in different states (call this 3):
Steubenville, OH-Weirton, WV
This one threw me for a loop; it makes sense but it flushes the previous formats (call this 4):
Kingsport, TN-Johnson City, TN-Bristol, VA-TN
In that example, Bristol is in both VA and TN. Then there's this (call this 5):
Mayagüez/Aguadilla-Ponce, PR
I'm okay with replacing the slash with a dash and processing the same as a previous example. That contains a diacritic as well and the rest of my data are diacritic-free. I'm okay with stripping the diacritic off, that seems to be somewhat straightforward in PHP.
Then there's my final example (call this 6):
Scranton--Wilkes-Barre--Hazleton, PA
The city name contains a dash so the delimiter between city names is a double dash.
What I'd like to produce is, given any of the above examples and a few hundred other lines that follow the same format, an array of [[city, state],...] for each so I can turn them into SQL. For example, parsing 4 would yield:
[
['Kingsport', 'TN'],
['Johnson City', 'TN'],
['Bristol', 'VA'],
['Bristol', 'TN']
]
I'm using a standard PHP install, I've got preg_match and so on but no PECL libraries. Order is unimportant.
Any thoughts on a good way to do this without a big pile of if-then statements?
I would split the input with '-'s and ','s, then delete empty elements in the array. str_replace followed by explode and array_diff (, array ()) should do the trick.
Then identify States - either searching a list or working on the principal that cities don't tend to have 2 upper-case letter names.
Now work through the array. If it's a city, save the name, if it's a state, apply it to the saved cities. Clear the list of cities when you get a city immediately following a state.
Note any exceptions and reformat by hand into a different input.
Hope this helps.
For anyone who's interested, I took the answer from #mike and came up with this:
function SplitLine($line) {
// This is over-simplified, just to cover the given case.
$line = str_replace('ü', 'u', $line);
// Cover case 6.
$delimiter = '-';
if (false !== strpos($line, '--'))
$delimiter = '--';
$line = str_replace('/', $delimiter, $line);
// Case 5 looks like case 2 now.
$parts = explode($delimiter, $line);
$table = array_map(function($part) { return array_map('trim', explode(',', $part)); }, $parts);
// At this point, table contains a grid with missing values.
for ($i = 0; $i < count($table); $i++) {
$row = $table[$i];
// Trivial case (case 1 and 3), go on.
if (2 == count($row))
continue;
if (preg_match('/^[A-Z]{2}$/', $row[0])) {
// Missing city; seek backwards.
$find = $i;
while (2 != count($table[$find]))
$find--;
$table[$i] = [$table[$find][0], $row[0]];
} else {
// Missing state; seek forwards.
$find = $i;
while (2 != count($table[$find]))
$find++;
$table[$i][] = $table[$find][1];
}
}
return $table;
}
It's not pretty and it's slow. It does cover all my cases and since I'm doing an ETL process the speed isn't paramount. There's also no error detection, which works in my particular case.

How to use number_format without thousands separator and round function

I have a doubt with how to use the number_format and round function together, this because I have an script to import all my supplier's products, but I need round the prices, for example:
Supplier's price: $1854.81
The price rounded: $1854.99 (This is the format that I want)
The price that my script print: $1,854.90
I tryed 3 PHP variant to do this:
Variant #1:
$preciosinr = 1854.81;
echo number_format(round($preciosinr*4)/4,2); //Print 1,854.90
Variant #2
$preciosinr = 1854.81;
$pos = 3 - floor(log10($preciosinr));
echo number_format(round($preciosinr,$pos)-0.10,2); //Print 1,854.75
Variant #3
$preciosinr = 1854.81;
number_format($preciosinr,2);
number_format(round($preciosinr,1),2);
number_format(round($preciosinr,0),2);
echo number_format(round($preciosinr,0)-0.01,2); //Print 1,854.99
As you can see all the variants prints the price with "," and I need the price without this because my system detect the price incorrectly.
I read in php.net that I need use the following sintaxis but I don't know how can integrate with my code.
// english notation without thousands separator
$english_format_number = number_format($number, 2, '.', '');
// 1234.57
Can you help me?
$price=number_format(round($preciosinr,0)-0.01,2,'.','');
echo $price;
This should work
I found it strange that the answer that was accepted is actually wrong.
Example case:
// The input we want to check
$stringNumber = '7616.95';
// As suggested by accepted answer
$formatted = number_format(round($stringNumber,0)-0.01,2,'.','' );
echo $formatted; // Outputs: 7616.99
A better solution is found here:
https://stackoverflow.com/a/7459107

10 random images with glob() from 1000+ images

i have a directory with 1000+ images and piece of code (by codaddict) which selects only first 10 and display it:
<?php
foreach (array_slice(glob("/directory/*.jpg"),0,10) as $path)
?>
ok this works, but i need to select 10 RANDOM images, not the first 10
yes, i can use shuffle first, then slice, but with 1000+ (or 10k+) images, it's not smart to shuffle long arrays just for 10 images, or maybe it is?
also, 2nd problem is that this is not just for one folder with 1000+ images, i need to use this script in other folders too, and some of them will only have 1 image, so i don't want to see errors if there is less than 10 images in a folder
i saw in php manual code for 2 random items, but i won't know how many images will be in folders - 1, 10, 10k... you see the problem
<?php
$input = array("Neo", "Morpheus", "Trinity", "Cypher", "Tank");
$rand_keys = array_rand($input, 2);
echo $input[$rand_keys[0]] . "\n";
echo $input[$rand_keys[1]] . "\n";
?>
thanks!
function imageGlobber($myDir, $imgCount) {
$globVar = glob($myDir."/*.jpg");
$imgCount = ($imgCount > count($globVar)) ? $imgCount : count($globVar);
$randKeys = array_rand($globVar, $imgCount);
$retArray = array();
foreach($randKeys as $key)
array_push($retArray, $globVar[$key]);
return $retArray;
}
I think this is what you are looking for.
Edit : Added duplicate handling as well.
Edit : Improved performance.

How to check if a text is contained into another?

I'm developing a documents system that, each time that a new one is created, it has to detect and discard duplicates in a database of about 500.000 records.
For now, I'm using a search engine to retrieve the 20 most similar documents, and compare them with the new one that we're trying to create. The problem is that I have to check if the new document is similar (that's easy with similar_text), or even if it's contained inside the other text, all this operations considering that the text may have been partly changed by the user (here is the problem). How I can do that?
For example:
<?php
$new = "the wild lion";
$candidates = array(
'the dangerous lion lives in Africa',//$new is contained into this one, but has changed 'wild' to 'dangerous', it has to be detected as duplicate
'rhinoceros are native to Africa and three to southern Asia.'
);
foreach ( $candidates as $candidate ) {
if( $candidate is similar or $new is contained in it) {
//Duplicated!!
}
}
Of course, in my system the documents are longer than 3 words :)
This is the temporal solution I'm using:
function contained($text1, $text2, $factor = 0.9) {
//Split into words
$pattern= '/((^\p{P}+)|(\p{P}*\s+\p{P}*)|(\p{P}+$))/u';
$words1 = preg_split($pattern, mb_strtolower($text1), -1, PREG_SPLIT_NO_EMPTY);
$words2 = preg_split($pattern, mb_strtolower($text2), -1, PREG_SPLIT_NO_EMPTY);
//Set long and short text
if (count($words1) > count($words2)) {
$long = $words1;
$short = $words2;
} else {
$long = $words2;
$short = $words1;
}
//Count the number of words of the short text that also are in the long
$count = 0;
foreach ($short as $word) {
if (in_array($word, $long)) {
$count++;
}
}
return ($count / count($short)) > $factor;
}
A few Ideas, that you could potentially undertake or investigate further are:
Indexing the documents and then searching for similar documents. So Open source Indexing/Search systems such as Solr, Sphinx or Zend Search Lucene could come in handy.
You could use the sim hashing algorithm or shingling . Briefly the simhash algorithm will let you compute similar hash values for similar documents. So you could then store this value against each document and check how similar various documents are.
Other algorithms that you may find helpful to get some ideas from are:
1 . Levenshtein distance
2 . Bayesian filtering - SO Questions re Bayesian filtering. First link in this list item points to the Bayesian spam filtering article on Wiki, but this algorithm can be adapted to what you are trying to do.

How to get last name first inital [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Regex - Return First and Last Name
Hi,
I have the full name of users stored in one field. How can i get the full first name and last name first initial. This is what i am using right now:
$first = substr($full_n, 0, strpos($full_n,' '));
list ($first, $last) = explode(' ', $full_n, 2);
echo "$first {$last[0]}.";
Will not work with more than two names too, like all the other solutions. You should save all (firstname, middle name, surname, ...) separatly, if you want to do more with it, than just displaying.
Update:
Inspired be Pekka (comments of the question ;))
$names = explode(' ', $full_n);
$first = array_shift($names);
$last = array_pop($names);
echo "$first {$last[0]}.";
This works for an arbitrary (>= 2) count of names, but will only display the first (complete) and the last (shortened). Something like "Schmidt-Mueller" will look curious ("S.").
Well, you're almost there...
If it's guaranteed that your users will have two names (just first and last, with no spaces in either), then you could just do this:
$full_n = 'Demian Brecht';
$first = substr($full_n, 0, strpos($full_n,' ')+2);
print_r($first);
However, if you're dealing with > 2 names, then you'll have to rethink your logic.
(not an answer but too big to be a comment)
There is no solution to this problem, you will just have to decide in what way will you mangle peoples names.
There are several decent examples in the answers already, but they will all fail on Pekka's examples in his comment. Some names like Hillary Rodham Clinton are often hyphenated Hillary Rodham-Clinton and will be less of a problem.
Simpler common examples such as John von Neumann or Phillip de la Cruz will still fail.
$full_n = trim($full_n); // remove extra spaces
$first_name = substr($full_n, 0, strpos($full_n, ' '));
$last_initial = substr($full_n, strrchr($full_n, ' '), 1);
$result = trim($first_name . ' ' . $last_initial);
I had a hard time understanding this question. If you want the full first name and the first initial of the last name.
$firstwithlastnameinitial = substr($full_n, 0, strpos($full_n, ' ')) . substr($full_n, strpos($full_n, ' ') + 1, 1);
OR
list ($fname, $lname) = explode(' ', $full_n, 2);
$lastwithfirstinitial = $fname . substr($lname, 0, 1);
If you want the full last name with first initial of the first name:
$lastwithfirstinitial = substr($full_n, strpos($full_n, ' ') + 1, strlen($full_n)) . substr($full_n, 0, 1);
This should retrieve the last name plus the first initial. Or something easier to read.
list ($fname, $lname) = explode(' ', $full_n, 2);
$lastwithfirstinitial = $lname . substr($fname, 0, 1);

Categories