I created a PHP script that checks the HTTP_ACCEPT_LANGUAGE and loads the website using the appropriate language from the 1st two characters:
$http_lang = substr($_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2);
switch ($http_lang) {
case 'en':
$SESSION->conf['language'] = 'english';
break;
case 'es':
$SESSION->conf['language'] = 'spanish';
break;
default:
$SESSION->conf['language'] = $PREFS->conf['languages'][$SESSION->conf['language_id']];
}
If I change the language to Spanish in Firefox the website loads in Spanish fine. However I have had several reports that people in Colombia see the website in english.
Details:
"es-co" LCID = 9226 Spanish(Colombia)
Anyone have any ideas as to why this is happening? I thought this was the best way to check what language users support.
A more contemporary method would be to use http_negotiate_language():
$map = array("en" => "english", "es" => "spanish");
$conf_language= $map[ http_negotiate_language(array_keys($map)) ];
If you don't have the http extension installed (and not the intl one as well), there is yet another workaround in the comments (user-note #86787 (Nov 2008; by Anonymous)):
<?php
/*
determine which language out of an available set the user prefers most
$available_languages array with language-tag-strings (must be lowercase) that are available
$http_accept_language a HTTP_ACCEPT_LANGUAGE string (read from $_SERVER['HTTP_ACCEPT_LANGUAGE'] if left out)
*/
function prefered_language ($available_languages,$http_accept_language="auto") {
// if $http_accept_language was left out, read it from the HTTP-Header
if ($http_accept_language == "auto") $http_accept_language = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';
// standard for HTTP_ACCEPT_LANGUAGE is defined under
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
// pattern to find is therefore something like this:
// 1#( language-range [ ";" "q" "=" qvalue ] )
// where:
// language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
// qvalue = ( "0" [ "." 0*3DIGIT ] )
// | ( "1" [ "." 0*3("0") ] )
preg_match_all("/([[:alpha:]]{1,8})(-([[:alpha:]|-]{1,8}))?" .
"(\s*;\s*q\s*=\s*(1\.0{0,3}|0\.\d{0,3}))?\s*(,|$)/i",
$http_accept_language, $hits, PREG_SET_ORDER);
// default language (in case of no hits) is the first in the array
$bestlang = $available_languages[0];
$bestqval = 0;
foreach ($hits as $arr) {
// read data from the array of this hit
$langprefix = strtolower ($arr[1]);
if (!empty($arr[3])) {
$langrange = strtolower ($arr[3]);
$language = $langprefix . "-" . $langrange;
}
else $language = $langprefix;
$qvalue = 1.0;
if (!empty($arr[5])) $qvalue = floatval($arr[5]);
// find q-maximal language
if (in_array($language,$available_languages) && ($qvalue > $bestqval)) {
$bestlang = $language;
$bestqval = $qvalue;
}
// if no direct hit, try the prefix only but decrease q-value by 10% (as http_negotiate_language does)
else if (in_array($langprefix,$available_languages) && (($qvalue*0.9) > $bestqval)) {
$bestlang = $langprefix;
$bestqval = $qvalue*0.9;
}
}
return $bestlang;
}
?>
I used the regex from #GabrielAnderson and devised this function which behaves according to RFC 2616 (when no quality value is given to a language, it defaults to 1).
When several languages share the same quality value, the most specific are given priority over the less specific ones. (this behaviour is not part of the RFC which provides no recommendation for this specific case)
function Get_Client_Prefered_Language ($getSortedList = false, $acceptedLanguages = false)
{
if (empty($acceptedLanguages))
$acceptedLanguages = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
// regex inspired from #GabrielAnderson on http://stackoverflow.com/questions/6038236/http-accept-language
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})*)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $acceptedLanguages, $lang_parse);
$langs = $lang_parse[1];
$ranks = $lang_parse[4];
// (create an associative array 'language' => 'preference')
$lang2pref = array();
for($i=0; $i<count($langs); $i++)
$lang2pref[$langs[$i]] = (float) (!empty($ranks[$i]) ? $ranks[$i] : 1);
// (comparison function for uksort)
$cmpLangs = function ($a, $b) use ($lang2pref) {
if ($lang2pref[$a] > $lang2pref[$b])
return -1;
elseif ($lang2pref[$a] < $lang2pref[$b])
return 1;
elseif (strlen($a) > strlen($b))
return -1;
elseif (strlen($a) < strlen($b))
return 1;
else
return 0;
};
// sort the languages by prefered language and by the most specific region
uksort($lang2pref, $cmpLangs);
if ($getSortedList)
return $lang2pref;
// return the first value's key
reset($lang2pref);
return key($lang2pref);
}
Example:
print_r(Get_Client_Prefered_Language(true, 'en,en-US,en-AU;q=0.8,fr;q=0.6,en-GB;q=0.4'));
Outputs:
Array
(
[en-US] => 1
[en] => 1
[en-AU] => 0.8
[fr] => 0.6
[en-GB] => 0.4
)
As you can notice, 'en-US' appears in first position despite the fact that 'en' was first in the given string.
So you could use this function and just replace your first line of code by:
$http_lang = substr(Get_Client_Prefered_Language(),0,2);
Do you know if this is happening for all visitors to your site from Colombia? Users are usually free to alter the language settings of their browsers — or to have them altered for them by whoever is in charge of the computer. As zerkms recommends, try logging IP addresses and their headers.
If you have the intl extension installed you can use Locale::lookup and Locale::acceptFromHttp to get a best-fit choice of language from the users browser settings and a list of what translations you have available.
Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']); # e.g. "en_US"
In the end I went with this solution:
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
if (count($lang_parse[1])){
$langs = array_combine($lang_parse[1], $lang_parse[4]);
foreach ($langs as $lang => $val){
if ($val === '') $langs[$lang] = 1;
}
arsort($langs, SORT_NUMERIC);
}
foreach ($langs as $lang => $val){
if (strpos($lang,'en')===0){
$language = 'english';
break;
} else if (strpos($lang,'es')===0){
$language = 'spanish';
}
}
}
I would like to thank AJ for the links. Also thanks to all that replied.
I will use full locale code to refer language, because like zh-TW and zh-CN is 2 different language.
function httpAcceptLanguage($httpAcceptLanguage = null)
{
if ($httpAcceptLanguage == null) {
$httpAcceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
}
$languages = explode(',', $httpAcceptLanguage);
$result = array();
foreach ($languages as $language) {
$lang = explode(';q=', $language);
// $lang == [language, weight], default weight = 1
$result[$lang[0]] = isset($lang[1]) ? floatval($lang[1]) : 1;
}
arsort($result);
return $result;
}
// zh-TW,en-US;q=0.7,en;q=0.3
echo $_SERVER['HTTP_ACCEPT_LANGUAGE'];
/*
Array
(
[zh-TW] => 1
[en-US] => 0.7
[en] => 0.3
)
*/
print_r(httpAcceptLanguage());
if you want to store languages in array, i do this:
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', 'pt-br,pt;q=0.8,en-us;q=0.5,en,en-uk;q=0.3', $lang_parse);
$langs = $lang_parse[1];
$rank = $lang_parse[4];
for($i=0; $i<count($langs); $i++){
if ($rank[$i] == NULL) $rank[$i] = $rank[$i+1];
}
this output an array to languages e other with values
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', 'pt-br,pt;q=0.8,en-us;q=0.5,en,en-uk;q=0.3', $lang_parse);
$langs = $lang_parse[1];
$rank = $lang_parse[4];
$lang = array();
for($i=0; $i<count($langs); $i++){
$lang[$langs[$i]] = ($rank[$i] == NULL) ? $rank[$i+1] : $rank[$i];
}
this output an array like this:
Array
(
[pt-br] => 0.8
[pt] => 0.8
[en-us] => 0.5
[en] => 0.3
[en-uk] => 0.3
)
I put my trust in the skilled programmers who work for PHP and think ahead.
Here is my version of a label for the Google translator drop down.
function gethttplanguage(){
$langs = array(
'en',// default
'it',
'dn',
'fr',
'es'
);
$questions = array(
"en" => "If you wish to see this site in another language click here",
"it" => "Se vuole vedere questo sito in italiano clicca qui",
"dn" => "Hvis du ønsker at se denne hjemmeside i danske klik her",
"fr" => "Si vous voulez visualiser ce site en français, cliquez ici",
"es" => "Si quieres ver este sitio en español haga clic aquí"
);
$result = array();
http_negotiate_language($langs, &$result);
return $questions[key($result)];
}
Related
I'm working on calculating the pass ratings of various football players. I have a .txt file that I'm pulling the info from.
while($line = fgetcsv($fp, 255, ',')){
$rate = round(calcPR($line),2);
$rating[$line[0]] = $rate;
} return $rating;
That was the portion of my function where I'm using a $fp to read from my .txt file and here is where I'm trying to display the data, but before I attempt to display my data I try to split the data into pass ratings that are great,good,mediocre, and poor.
For a great rating, they need to be above 95 so I have:
$grtRating = array_filter($rating,function(){
return $rating > 95;
});
The rest of my code for good, mediocre, and poor looks just about the same, but with different criteria. How can I get this $grtRating array to store only the scores that are above 95?
Currently when I run my program it basically ignores the operators and displays all of the ratings no matter how low.
UPDATE:
Output of $poorRating array: (This is everything < 86)
Array ( [Cody Kessler] => 85.91 [Kirk Cousins] => 82.34 [Jacoby Brissett] => 81.68 [Ryan Tannehill] => 81.2 [Tyrod Taylor] => 79.29 [Ben Roethlisberger] => 77.49 [Shaun Hill] => 77.32 [Carson Palmer] => 74.79 [Jameis Winston] => 73.93 [Marcus Mariota] => 73.06 [Joe Flacco] => 71.77 [Cam Newton] => 70.32 [Josh McCown] => 70.25 [Trevone Boykin] => 69.2 [Jay Cutler] => 68.46 [Blake Bortles] => 67.13 [Brock Osweiler] => 66.1 [Blaine Gabbert] => 63.35 [Case Keenum] => 60.63 [Ryan Fitzpatrick] => 48.93 [Robert Griffin III] => 48.54 [Drew Stanton] => 34.36 [Kellen Clemens] => 2.07 )
I think the problem might be in how I output my code then. I have my links in an unordered list.
Here is an example:
<a href='pr.php?action=all'>All Ratings</a>
I have a pr.php?action=great',pr.php?action=good', pr.php?action=mediocre', andpr.php?action='poor'.
Here is how I output everything, is the problem how I do that?
$mode = 'all';
if ($_GET['action'] == 'great') $mode = 'great';
if ($_GET['action'] == 'good') $mode = 'good';
if ($_GET['action'] == 'mediocre') $mode = 'mediocre';
if ($_GET['action'] == 'poor') $mode = 'poor';
if($mode == 'great'){
foreach($greatRating as $name=>$pr){
echo "<tr><td>{$name}</td><td>{$pr}</td></tr>\n";
}
}
if($mode == 'good'){
foreach($goodRating as $name=>$pr){
echo "<tr><td>{$name}</td><td>{$pr}</td></tr>\n";
}
}
if($mode == 'mediocre'){
foreach($mediocreRating as $name=>$pr){
echo "<tr><td>{$name}</td><td>{$pr}</td></tr>\n";
}
}
if($mode == 'poor'){
foreach($poorRating as $name=>$pr){
echo "<tr><td>{$name}</td><td>{$pr}</td></tr>\n";
}
}
if($mode = 'all'){
foreach($rating as $name=>$pr){
echo "<tr><td>{$name}</td><td>{$pr}</td></tr>\n";
}
}
echo "</table></div>\n";
}
Would you please help me figure out where my error is?
Replace
$grtRating = array_filter($rating,function(){
return $rating > 95;
});
with
$grtRating = array_filter($rating, function($val) {
return $val > 95;
});
In the first one, you did not include the callback argument that contains the value passed from each iteration of the array, which will be the one used in your evaluation.
I faced an interview question which i felt was very good. Couldn't achieve the complete answer, however, felt sharing and asking the right method to code it in PHP.
The question goes as :
Given the Japanese numeral reading system, write a program that converts an integer into the equivalent Japanese reading.
Basic numeral readings:
1: ichi
2: ni
3: san
4: yon
5: go
6: roku
7: nana
8: hachi
9: kyuu
10: juu
20: ni-juu
30: san-juu
100: hyaku
1000 : sen
10,000: man
100,000,000: oku
1,000,000,000,000: chou
10,000,000,000,000,000: kei
Exceptions due to voice rounding in Japanese reading:
300: sanbyaku
600: roppyaku
800: happyaku
3000: sanzen
8000: hassen
1,000,000,000,000: itchou
8,000,000,000,000: hatchou
10,000,000,000,000: jutchou (also applies to multiplies of 10,000,000,000,000)
10,000,000,000,000,000: ikkei
60,000,000,000,000,000: rokkei
80,000,000,000,000,000: hakkei
100,000,000,000,000,000: jukkei (also applies to multiplies of 10,000,000,000,000,000)
1,000,000,000,000,000,000: hyakkei (also applies to multiplies of 1,000,000,000,000,000,000)
Starting at 10,000, numbers begin with ichi if no digit would otherwise precede, e.g. 1,000 is sen but 10,000 is ichi-man.
Examples:
11: juu ichi
17: juu nana
151: hyaku go-juu ichi
302: san-byaku ni
469: yon-hyaku roku-juu kyuu
2025 : ni-sen ni-juu go
10,403: ichi-man yon-byaku san
41,892: yon-juu ichi-man happyaku kyuu-juu ni
80,000,000,000,000: hachi-jutchou
The code that i have tried is :
$inputNumber = 2025;
$inputString = (String)$inputNumber;
$numeralReadings = array(
1 => 'ichi',
2 => 'ni',
3 => 'san',
4 => 'yon',
5 => 'go',
6 => 'roku',
7 => 'nana',
8 => 'hachi',
9 => 'kyuu',
10 => 'juu',
20 => 'ni-juu',
30 => 'san-juu',
100 => 'hyaku',
1000 => 'sen',
10000 => 'man',
100000000 => 'oku',
1000000000000 => 'chou',
10000000000000000 => 'kei'
);
$numeralExceptions = array(
300 => 'sanbyaku',
600 => 'roppyaku',
800 => 'happyaku',
3000 => 'sanzen',
8000 => 'hassen',
1000000000000 => 'itchou',
8000000000000 => 'hatchou',
10000000000000 => 'jutchou',
10000000000000000 => 'ikkei',
60000000000000000 => 'rokkei',
80000000000000000 => 'hakkei',
100000000000000000 => 'jukkei',
1000000000000000000 => 'hyakkei'
);
if ($inputString > 10000) {
$inp1 = floor($inputString / 1000);
$inp = $inputString - ($inp1 * 1000);
if($inp !== 0) {
read($inp1, $numeralReadings, $numeralExceptions, false);
read($inp, $numeralReadings, $numeralExceptions);
} else {
read($inputString, $numeralReadings, $numeralExceptions);
}
} else {
read($inputString, $numeralReadings, $numeralExceptions);
}
function read($inputStr, $numeralReadings, $numeralExceptions, $parse1 = true)
{
$splitString = str_split($inputStr);
$returnString = '';
$appendIchi = false;
$firstNumber = null;
foreach ($splitString as $key => $number) {
if ($firstNumber == null) {
$firstNumber = $number;
}
if ($number !== 0) {
$int = 1;
$a = count($splitString) - 1 - $key;
for ($i = 0; $i < $a; $i++) {
$int = $int * 10;
}
$tempNumber = (int)$number * $int;
if (isset($numeralExceptions[$tempNumber])) {
$returnString .= $numeralExceptions[$tempNumber] . ' ';
continue;
}
if (isset($numeralReadings[$tempNumber])) {
if ($parse1 == false && $tempNumber == 1) {
continue;
}
$returnString .= $numeralReadings[$tempNumber] . ' ';
continue;
}
if (isset($numeralReadings[(int)$number])) {
if ($parse1 == false && $tempNumber == 1) {
continue;
}
$returnString .= $numeralReadings[(int)$number];
if ($int !== 1) {
$returnString .= '-' . $numeralReadings[$int];
}
$returnString .= ' ';
}
}
}
echo $returnString;
}
here is a fiddle that shows the code in running. You might want to try it online. Link
With the code above, i was able to achieve all the examples stated above other than the last 2.
Anyone who can solve this in a better way?
I guess you can simply use array_key_exists() here
function read($inputStr, $numeralReadings, $numeralExceptions)
{
if(array_key_exists($inputStr, $numeralReadings))
{
return $numeralReadings[$inputStr];
}
else if(array_key_exists($inputStr, $numeralExceptions))
{
return $numeralExceptions[$inputStr];
}
else
{
return "not found";
}
}
I am using WPML language, and cant find solution for next thing:
On the Language switcher i want to hide language, lets say for example - "he", if current language is lets say for example "ar", so when we on arabic site we will not see on the selector the Hebrew, and same thing if we on Hebrew, the arabic will not display.
On shorten words: what i want is - if we on arabic site - the hebrew flag will be hidden.
What i tried:
function language_selector_flags(){
$languages = icl_get_languages('skip_missing=0');
if(!empty($languages)){
if(ICL_LANGUAGE_CODE=='en')
{
$order = array('ar'); //Specify your sort order here
}
elseif(ICL_LANGUAGE_CODE=='he')
{
$order = array('en', 'ar'); //Specify your sort order here
}
foreach ($order as $l) {
if (isset($languages[$l])) {
$l = $languages[$l]; //grab this language from the unsorted array that is returned by icl_get_languages()
//Display whatever way you want -- I'm just displaying flags in anchors (CSS: a {float:left; display:block;width:18px;height:12px;margin:0 2px;overflow:hidden;line-height:100px;})
if($l['active']) { $class = "active"; $url=""; } else { $class = ''; $url = 'href="'.$l['url'].'"'; }
echo '<a '.$url.' style="background:url('.$l['country_flag_url'].') no-repeat;" class="flag '.$class.'">';
echo $l['language_code'].'';
}
}
}
}
Its not affect at all the selector.
You can check out the plugin WPML Flag In Menu.
You could use the plugin_wpml_flag_in_menu() function from the plugin (see source code here) and replace:
// Exclude current viewing language
if( $l['language_code'] != ICL_LANGUAGE_CODE )
{
// ...
}
with
// Include only the current language
if( $l['language_code'] == ICL_LANGUAGE_CODE )
{
// ...
}
to show only the current language/flag, if I understand you correctly.
ps: If you need further assistance, you could for exampe show us the output of this debug function for the active language:
function debug_icl_active_language()
{
$languages = icl_get_languages( 'skip_missing=0' );
foreach( (array) $languages as $l )
{
if( $l['active'] )
{
printf( '<pre> Total languages: %d - Active: %s </pre>',
count( $languages ),
print_r( $l, TRUE ) );
}
}
}
i have some useful link for you, please go through it first:
http://wpml.org/forums/topic/hide-language-vs-display-hidden-languages-in-your-profile-not-working/
http://wpml.org/forums/topic/hide-one-language/
http://wpml.org/forums/topic/hiding-active-language-in-menu/
http://wpml.org/forums/topic/language-selector-how-to-hide-one-language/
thanks
function language_selector_flags(){
$languages = icl_get_languages('skip_missing=0');
if(!empty($languages)){
$filter = array();
$filter['ar'] = array( 'he' );
// set your other filters here
$active_language = null;
foreach ($languages as $l)
if($l['active']) {
$active_language = $l['language_code'];
break;
}
$filter = $active_language && isset( $filter[$active_language] ) ? $filter[$active_language] : array();
foreach ($languages as $l) {
//Display whatever way you want -- I'm just displaying flags in anchors (CSS: a {float:left; display:block;width:18px;height:12px;margin:0 2px;overflow:hidden;line-height:100px;})
if( in_array( $l['language_code'], $filter) )
continue;
if($l['active']) { $class = "active"; $url=""; } else { $class = ''; $url = 'href="'.$l['url'].'"'; }
echo '<a '.$url.' class="flag '.$class.'"><img src="', $l['country_flag_url'], '" alt="', esc_attr( $l['language_code'] ), '" /></a>';
}
}
}
EDIT: If I get this right, your client(I assume) doesn't want his customers (Israelis especiay) to know that he offer service also to the arabic speaking cusomers. If it so then you can parse the Accept-Language header and filter the language selector according the result.
I have a similar problem/issue:
On this website: https://neu.member-diving.com/
I have languages I not need in the switcher. I tried the code above, but it nothing changed so far.
So, what I would like to do is, When a client is on the one "german" page, the other german languages in the switcher should not need to be there, only the english one and the actual german one.
Where do I need to put code like
function language_selector_flags(){
$languages = icl_get_languages('skip_missing=0');
if(!empty($languages)){
$filter = array();
$filter['ar'] = array( 'he' );
// set your other filters here
$active_language = null;
foreach ($languages as $l)
if($l['active']) {
$active_language = $l['language_code'];
break;
}
$filter = $active_language && isset( $filter[$active_language] ) ? $filter[$active_language] : array();
foreach ($languages as $l) {
//Display whatever way you want -- I'm just displaying flags in anchors (CSS: a {float:left; display:block;width:18px;height:12px;margin:0 2px;overflow:hidden;line-height:100px;})
if( in_array( $l['language_code'], $filter) )
continue;
if($l['active']) { $class = "active"; $url=""; } else { $class = ''; $url = 'href="'.$l['url'].'"'; }
echo '<a '.$url.' class="flag '.$class.'"><img src="', $l['country_flag_url'], '" alt="', esc_attr( $l['language_code'] ), '" /></a>';
}
}
}
Given a source text like
nin2 hao3 ma
(which is a typical way to write ASCII Pinyin, without proper accentuated characters)
and given a (UTF8) conversion table like
a1;ā
e1;ē
i1;ī
o1;ō
u1;ū
ü1;ǖ
A1;Ā
E1;Ē
...
how would I convert the source text into
nín hǎo ma
?
For what it's worth I'm using PHP, and this might be a regex I'm looking into?
Ollie's algorithm was a nice start, but it didn't apply the marks correctly. For example, qiao1 became qīāō. This one is correct and complete. You can easily see how the replacement rules are defined.
It does the whole thing for tone 5 as well, although it doesn't affect the output, except for deleting the number. I left it in, in case you want to do something with tone 5.
The algorithm works as follows:
The word and tone are provided in $match[1] and [2]
A star is added behind the letter that should get the accent mark
A letter with a star is replaced by that letter with the correct tone mark.
Example:
qiao => (iao becomes ia*o) => qia*o => qiǎo
This strategy, and the use of strtr (which prioritizes longer replacements), makes sure that this won't happen:
qiao1 => qīāō
function pinyin_addaccents($string) {
# Find words with a number behind them, and replace with callback fn.
return preg_replace_callback(
'~([a-zA-ZüÜ]+)(\d)~',
'pinyin_addaccents_cb',
$string);
}
# Helper callback
function pinyin_addaccents_cb($match) {
static $accentmap = null;
if( $accentmap === null ) {
# Where to place the accent marks
$stars =
'a* e* i* o* u* ü* '.
'A* E* I* O* U* Ü* '.
'a*i a*o e*i ia* ia*o ie* io* iu* '.
'A*I A*O E*I IA* IA*O IE* IO* IU* '.
'o*u ua* ua*i ue* ui* uo* üe* '.
'O*U UA* UA*I UE* UI* UO* ÜE*';
$nostars = str_replace('*', '', $stars);
# Build an array like Array('a' => 'a*') and store statically
$accentmap = array_combine(explode(' ',$nostars), explode(' ', $stars));
unset($stars, $nostars);
}
static $vowels =
Array('a*','e*','i*','o*','u*','ü*','A*','E*','I*','O*','U*','Ü*');
static $pinyin = Array(
1 => Array('ā','ē','ī','ō','ū','ǖ','Ā','Ē','Ī','Ō','Ū','Ǖ'),
2 => Array('á','é','í','ó','ú','ǘ','Á','É','Í','Ó','Ú','Ǘ'),
3 => Array('ǎ','ě','ǐ','ǒ','ǔ','ǚ','Ǎ','Ě','Ǐ','Ǒ','Ǔ','Ǚ'),
4 => Array('à','è','ì','ò','ù','ǜ','À','È','Ì','Ò','Ù','Ǜ'),
5 => Array('a','e','i','o','u','ü','A','E','I','O','U','Ü')
);
list(,$word,$tone) = $match;
# Add star to vowelcluster
$word = strtr($word, $accentmap);
# Replace starred letter with accented
$word = str_replace($vowels, $pinyin[$tone], $word);
return $word;
}
<?php
$in = 'nin2 hao3 ma';
$out = 'nín hǎo ma';
function replacer($match) {
static $trTable = array(
1 => array(
'a' => 'ā',
'e' => 'ē',
'i' => 'ī',
'o' => 'ō',
'u' => 'ū',
'ü' => 'ǖ',
'A' => 'Ā',
'E' => 'Ē'),
2 => array('i' => 'í'),
3 => array('a' => 'ǎ')
);
list(, $word, $i) = $match;
return str_replace(
array_keys($trTable[$i]),
array_values($trTable[$i]),
$word); }
// Outputs: bool(true)
var_dump(preg_replace_callback('~(\w+)(\d+)~', 'replacer', $in) === $out);
For a .NET solution try Pinyin4j.NET
Features
Convert Chinese (both Simplified and Traditional) to most popular pinyin systems. Supporting pinyin system are listed below.
Hanyu Pinyin 汉语拼音
Tongyong Pinyin 通用拼音
Wade-Giles 威妥玛拼音
MPS2 (Mandarin Phonetic Symbols II) 国语注音符号第二式
Yale Romanization 耶鲁罗马化拼音
Gwoyeu Romatzyh国语国语罗马化拼音
To add a javascript solution:
This code places Tonemarks according to the official algorithm for placing one,
see wikipedia.
Hope that helps some of you, suggestions and improvements wellcome!
var ACCENTED = {
'1': {'a': '\u0101', 'e': '\u0113', 'i': '\u012B', 'o': '\u014D', 'u': '\u016B', 'ü': '\u01D6'},
'2': {'a': '\u00E1', 'e': '\u00E9', 'i': '\u00ED', 'o': '\u00F3', 'u': '\u00FA', 'ü': '\u01D8'},
'3': {'a': '\u01CE', 'e': '\u011B', 'i': '\u01D0', 'o': '\u01D2', 'u': '\u01D4', 'ü': '\u01DA'},
'4': {'a': '\u00E0', 'e': '\u00E8', 'i': '\u00EC', 'o': '\u00F2', 'u': '\u00F9', 'ü': '\u01DC'},
'5': {'a': 'a', 'e': 'e', 'i': 'i', 'o': 'o', 'u': 'u', 'ü': 'ü'}
};
function getPos (token) {
if (token.length === 1){
// only one letter, nothing to differentiate
return 0;
}
var precedence = ['a', 'e', 'o'];
for (i=0; i<precedence.length; i += 1){
var pos = token.indexOf(precedence[i]);
// checking a before o, will take care of ao automatically
if (pos >= 0){
return pos;
}
}
var u = token.indexOf('u');
var i = token.indexOf('i');
if (i < u){
// -iu OR u-only case, accent goes to u
return u;
} else {
// -ui OR i-only case, accent goes to i
return i;
}
// the only vowel left is ü
var ü = token.indexOf('ü');
if (ü >= 0){
return ü;
}
}
//and finally:
// we asume the input to be valid PinYin, therefore no security checks....
function placeTone(numbered_PinYin){
var ToneIndex = numbered_PinYin.charAt(numbered_PinYin.length -1);
var accentpos = getPos(numbered_PinYin);
var accented_Char = ACCENTED[ToneIndex][numbered_PinYin.charAt(accentpos)];
var accented_PinYin = "";
if (accentpos === 0){
// minus one to trimm the number off
accented_PinYin = accented_Char + numbered_PinYin.substr(1, numbered_PinYin.length-1);
} else {
var before = numbered_PinYin.substr(0, accentpos);
var after = numbered_PinYin.substring(accentpos+1, numbered_PinYin.length-1);
accented_PinYin = before + accented_Char + after;
}
return accented_PinYin;
}
console.log(placeTone('han4 zi4'));
VB Macro (Libre)Office : Convert pinyin tone numbers to accents
Hopefully the algorithm is correct accordingly to pinyin rules specially for i and u.
sub replaceNumberByTones
call PinyinTonesNumber("a([a-z]*[a-z]*)0", "a$1")
call PinyinTonesNumber("a([a-z]*[a-z]*)1", "a$1")
call PinyinTonesNumber("a([a-z]*[a-z]*)2", "á$1")
call PinyinTonesNumber("a([a-z]*[a-z]*)3", "a$1")
call PinyinTonesNumber("a([a-z]*[a-z]*)4", "à$1")
call PinyinTonesNumber("o([a-z]*[a-z]*)0", "o$1")
call PinyinTonesNumber("o([a-z]*[a-z]*)1", "o$1")
call PinyinTonesNumber("o([a-z]*[a-z]*)2", "ó$1")
call PinyinTonesNumber("o([a-z]*[a-z]*)3", "o$1")
call PinyinTonesNumber("o([a-z]*[a-z]*)4", "ò$1")
call PinyinTonesNumber("e([a-z]*[a-z]*)0", "e$1")
call PinyinTonesNumber("e([a-z]*[a-z]*)1", "e$1")
call PinyinTonesNumber("e([a-z]*[a-z]*)2", "é$1")
call PinyinTonesNumber("e([a-z]*[a-z]*)3", "e$1")
call PinyinTonesNumber("e([a-z]*[a-z]*)4", "è$1")
call PinyinTonesNumber("u([a-hj-z]*[a-hj-z]*)0", "u$1")
call PinyinTonesNumber("u([a-hj-z]*[a-hj-z]*)1", "u$1")
call PinyinTonesNumber("u([a-hj-z]*[a-hj-z]*)2", "ú$1")
call PinyinTonesNumber("u([a-hj-z]*[a-hj-z]*)3", "u$1")
call PinyinTonesNumber("u([a-hj-z]*[a-hj-z]*)4", "ù$1")
call PinyinTonesNumber("i([a-z]*[a-z]*)0", "i$1")
call PinyinTonesNumber("i([a-z]*[a-z]*)1", "i$1")
call PinyinTonesNumber("i([a-z]*[a-z]*)2", "í$1")
call PinyinTonesNumber("i([a-z]*[a-z]*)3", "i$1")
call PinyinTonesNumber("i([a-z]*[a-z]*)4", "ì$1")
End sub
sub PinyinTonesNumber(expression, replacement)
rem ----------------------------------------------------------------------
rem define variables
dim document as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ----------------------------------------------------------------------
dim args1(18) as new com.sun.star.beans.PropertyValue
args1(0).Name = "SearchItem.StyleFamily"
args1(0).Value = 2
args1(1).Name = "SearchItem.CellType"
args1(1).Value = 0
args1(2).Name = "SearchItem.RowDirection"
args1(2).Value = true
args1(3).Name = "SearchItem.AllTables"
args1(3).Value = false
args1(4).Name = "SearchItem.Backward"
args1(4).Value = false
args1(5).Name = "SearchItem.Pattern"
args1(5).Value = false
args1(6).Name = "SearchItem.Content"
args1(6).Value = false
args1(7).Name = "SearchItem.AsianOptions"
args1(7).Value = false
args1(8).Name = "SearchItem.AlgorithmType"
args1(8).Value = 1
args1(9).Name = "SearchItem.SearchFlags"
args1(9).Value = 65536
args1(10).Name = "SearchItem.SearchString"
args1(10).Value = expression
args1(11).Name = "SearchItem.ReplaceString"
args1(11).Value = replacement
args1(12).Name = "SearchItem.Locale"
args1(12).Value = 255
args1(13).Name = "SearchItem.ChangedChars"
args1(13).Value = 2
args1(14).Name = "SearchItem.DeletedChars"
args1(14).Value = 2
args1(15).Name = "SearchItem.InsertedChars"
args1(15).Value = 2
args1(16).Name = "SearchItem.TransliterateFlags"
args1(16).Value = 1280
args1(17).Name = "SearchItem.Command"
args1(17).Value = 3
args1(18).Name = "Quiet"
args1(18).Value = true
dispatcher.executeDispatch(document, ".uno:ExecuteSearch", "", 0, args1())
end sub
Hope this helps someone
François
How to get list of functions that are declared in a php file
You can get a list of currently defined function by using get_defined_functions():
$arr = get_defined_functions();
var_dump($arr['user']);
Internal functions are at index internal while user-defined function are at index user.
Note that this will output all functions that were declared previous to that call. Which means that if you include() files with functions, those will be in the list as well. There is no way of separating functions per-file other than making sure that you do not include() any file prior to the call to get_defined_functions().
If you must have the a list of functions per file, the following will attempt to retrieve a list of functions by parsing the source.
function get_defined_functions_in_file($file) {
$source = file_get_contents($file);
$tokens = token_get_all($source);
$functions = array();
$nextStringIsFunc = false;
$inClass = false;
$bracesCount = 0;
foreach($tokens as $token) {
switch($token[0]) {
case T_CLASS:
$inClass = true;
break;
case T_FUNCTION:
if(!$inClass) $nextStringIsFunc = true;
break;
case T_STRING:
if($nextStringIsFunc) {
$nextStringIsFunc = false;
$functions[] = $token[1];
}
break;
// Anonymous functions
case '(':
case ';':
$nextStringIsFunc = false;
break;
// Exclude Classes
case '{':
if($inClass) $bracesCount++;
break;
case '}':
if($inClass) {
$bracesCount--;
if($bracesCount === 0) $inClass = false;
}
break;
}
}
return $functions;
}
Use at your own risk.
You can use get_defined_functions() before and after you include the file, and look at what gets added to the array the second time. Since they appear to be in order of definition, you can just use the index like this:
$functions = get_defined_functions();
$last_index = array_pop(array_keys($functions['user']));
// Include your file here.
$functions = get_defined_functions();
$new_functions = array_slice($functions['user'], $last_index);
You can use the get_defined_functions() function to get all defined function in your current script.
See: http://www.php.net/manual/en/function.get-defined-functions.php
If you want to get the functions defined in another file, you can try using http://www.php.net/token_get_all like this:
$arr = token_get_all(file_get_contents('anotherfile.php'));
Then you can loop through to find function tokens with the symbols defined. The list of tokens can be found http://www.php.net/manual/en/tokens.php
If you're not worried about catching some commented out ones, this might be the simplest way:
preg_match_all('/function (\w+)/', file_get_contents(__FILE__), $m);
var_dump($m[1]);
I wrote this small function to return the functions in a file.
https://gist.github.com/tonylegrone/8742453
It returns a simple array of all the function names. If you're calling it in the particular file you want to scan, you can just use the following:
$functions = get_functions_in_file(__FILE__);
I solved this problem with array_diff
$funcs = get_defined_functions()["user"];
require_once 'myFileWithNewFunctions.php'; // define function testFunc() {} here
var_dump( array_values( array_diff(get_defined_functions()["user"], $funcs) ) )
// output: array[ 0 => "test_func"]
Update
To get the "real" functions name try this
foreach($funcsDiff AS $newFunc) {
$func = new \ReflectionFunction($newFunc);
echo $func->getName(); // testFunc
}
Well for what ever reason if you need to do this I show you:
Example file: Functions.php (I just wrote some random shit does not Mather it works with everything)
<?php
// gewoon een ander php script. door het gebruiken van meerdere includes kun je gemakkelijk samen aan één app werken
function johannes($fnaam, $mode, $array){
switch ($mode) {
case 0:
echo "
<center>
<br><br><br><br><br>
he johannes!<br><br>
klik hier voor random text:<br>
<input type='submit' value='superknop' id='btn' action='randomding' level='0' loadloc='randomshit' />
<p id='randomshit'></p>
</center>
";
break;
case 1:
echo "bouw formulier";
break;
case 2:
echo "verwerk formulier";
break;
default:
echo "[Error: geen mode gedefinieerd voor functie '$fnaam'!]";
}
}
function randomding($fnaam, $mode, $array){
$randomar = array('He pipo wat mot je!','bhebhehehehe bheeeee. rara wie ben ik?','poep meloen!','He johannes, wat doeeeeee je? <input type="text" name="doen" class="deze" placeholder="Wat doe je?" /> <input type="button" value="vertellen!" id="btn" action="watdoetjho" level="0" loadloc="hierzo" kinderen="deze"> <p id="hierzo"></p>','knopje de popje opje mopje','abcdefghijklmnopqrstuvwxyz, doe ook nog mee','Appien is een **p!!!!!! hahhahah<br><br><br><br> hahaha','Ik weet eiegelijk niks meer te verzinnen','echt ik weet nu niks meer','nou oke dan[[][(!*($##&*$*^éäåðßð','he kijk een microboat: <br> <img src="https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcS_n8FH6xzf24kEc31liZF6ULHCn2IINFurlFZ_G0f0_F4sLTi74w" alt="microboat" />');
$tellen = count($randomar);
$tellen--;
$rand = rand(0, $tellen);
echo $randomar[$rand];
}
function watdoetjho($fnaam, $mode, $array){
$dit = $array['doen'];
echo "Johannes is: $dit";
}
?>
We have 3 functions inside here:
johannes
randomding
watdoetjho
But we also call these functions:
count
rand
If we use get_defined_functions we will get all functions inside scope of script. Yes the PHP functions are separated from the user declared ones but still we want from a specific file.
If we use token_get_all we will receive a large amount of data we need to separate first.
I found these number which we need to make some connections inside the array to match the user functions. Otherwise we will have a list including all of php functions which are called upon.
The numbers are:
334 (List of all the user declared functions)
307 (List of all the function names)
If we filter the array to take all the 334 elements we have this:
334 -|- function -|- 5
But we need the function name and all the array elements are in relation with the 3rd value. So now we need to filter all the array elements which match the 3rd value (5) and the constant number 307.
This will give us something like this:
307 -|- johannes -|- 5
Now in PHP it will look like this:
<?php
error_reporting(E_ALL ^ E_NOTICE); // Or we get these undefined index errors otherwise use other method to search array
// Get the file and get all PHP language tokens out of it
$arr = token_get_all(file_get_contents('Functions.php'));
//var_dump($arr); // Take a look if you want
//The array where we will store our functions
$functions = array();
// loop trough
foreach($arr as $key => $value){
//filter all user declared functions
if($value[0] == 334){
//Take a look for debug sake
//echo $value[0] .' -|- '. $value[1] . ' -|- ' . $value[2] . '<br>';
//store third value to get relation
$chekid = $value[2];
}
//now list functions user declared (note: The last check is to ensure we only get the first peace of information about the function which is the function name, else we also list other function header information like preset values)
if($value[2] == $chekid && $value[0] == 307 && $value[2] != $old){
// just to see what happens
echo $value[0] .' -|- '. $value[1] . ' -|- ' . $value[2] . '<br>';
$functions[] = $value[1];
$old = $chekid;
}
}
?>
Result in this case is:
307 -|- johannes -|- 5
307 -|- randomding -|- 31
307 -|- watdoetjho -|- 43
To get list of defined and used functions in code, with small useful file manager, you can use code below. Enjoy!
if ((!function_exists('check_password'))||(!check_password()) ) exit('Access denied.'); //...security!
echo "<html><body>";
if (!$f) echo nl2br(htmlspecialchars('
Useful parameters:
$ext - allowed extensions, for example: ?ext=.php,css
$extI - case-insensitivity, for example: ?extI=1&ext=.php,css
'));
if (($f)&&(is_readable($_SERVER['DOCUMENT_ROOT'].$f))&&(is_file($_SERVER['DOCUMENT_ROOT'].$f))) {
echo "<h3>File <strong>$f</strong></h3>\n";
if(function_exists('get_used_functions_in_code')) {
echo '<h3>Used:</h3>';
$is=get_used_functions_in_code(file_get_contents($_SERVER['DOCUMENT_ROOT'].$f));
sort($is);
$def=get_defined_functions();
$def['internal']=array_merge($def['internal'], array('__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'finally', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while'));
foreach ($def['user'] as &$e) $e=strtolower($e); unset($e);
foreach ($is as &$e) if (!in_array(strtolower($e), $def['internal'], TRUE)) $e='<span style="color: red">'.$e.'</span>'; unset($e); //user-defined functions will be red
echo implode('<br />'.PHP_EOL,$is);
}
else echo "Error: missing function 'get_used_functions_in_code' !";
if(function_exists('get_defined_functions_in_code')) {
echo '<br /><h3>Defined:</h3>';
$is=get_defined_functions_in_code(file_get_contents($_SERVER['DOCUMENT_ROOT'].$f));
sort($is);
echo implode('<br />',$is);
}
else echo "Error: missing function 'get_defined_functions_in_code' !";
}
/*
File manager
*/
else {
if (!function_exists('select_icon')) {
function select_icon($name) {$name = pathinfo($name); return '['.$name["extension"].']';}
}
if($ext) $extensions=explode(',',strrev($ext));
if(!$f) $f=dirname($_SERVER['PHP_SELF']);
echo "<h3>Dir ".htmlspecialchars($f)."</h3><br />\n<table>";
$name=scandir($_SERVER['DOCUMENT_ROOT'].$f);
foreach($name as $name) {
if (!($fileOK=(!isset($extensions)))) {
foreach($extensions as $is) if (!$fileOK) $fileOK=((strpos(strrev($name),$is)===0)||($extI &&(stripos(strrev($name),$is)===0)));
}
$is=is_dir($fullName=$_SERVER['DOCUMENT_ROOT']."$f/$name");
if ($is || $fileOK) echo '<tr><td>'.select_icon($is ? 'x.folder' : $name).' </td><td> '.($is ? '[' : '').''.htmlspecialchars($name).''.($is ? ']' : '').'</td>';
if ($is) echo '<td> </td><td> </td>';
elseif ($fileOK) echo '<td style="text-align: right"> '.number_format(filesize($fullName),0,"."," ").' </td><td> '.date ("Y.m.d (D) H:i",filemtime($fullName)).'</td>';
if ($is || $fileOK) echo '</tr>'.PHP_EOL;
}
echo "\n</table>\n";
}
echo "<br /><br />".date ("Y.m.d (D) H:i")."</body></html>";
return;
/********************************************************************/
function get_used_functions_in_code($source) {
$tokens = token_get_all($source);
$functions = array();
$thisStringIsFunc = 0;
foreach($tokens as $token) {
if(($token[0]!=T_WHITESPACE)&&((!is_string($token))||($token[0]!='('))) unset($func);
if((is_array($token))&&(in_array($token[0],array(T_EVAL,T_EXIT,T_INCLUDE,T_INCLUDE_ONCE,T_LIST,T_REQUIRE,T_REQUIRE_ONCE,T_RETURN,T_UNSET)))) {$token[0]=T_STRING;$thisStringIsFunc=1;}
switch($token[0]) {
case T_FUNCTION: $thisStringIsFunc=-1;
break;
case T_STRING:
if($thisStringIsFunc>0) {
if (!in_array(strtoupper($token[1]),$functionsUp)) {$functions[]=$token[1];$functionsUp[]=strtoupper($token[1]);}
$thisStringIsFunc = 0;
} elseif ($thisStringIsFunc+1>0) {
$func = $token[1];
} else $thisStringIsFunc = 0;
break;
case '(':if($func) if(!in_array(strtoupper($func),$functionsUp)) {$functions[]=$func;$functionsUp[]=strtoupper($func);}
}
}
return $functions;
}
/********************************************/
function get_defined_functions_in_code($source) {
$tokens = token_get_all($source);
... then Andrew code (get_defined_functions_in_file) (https://stackoverflow.com/a/2197870/9996503)
}
Finding string (eg. Function names) in a file is simple with regex.
Just read the file and parse the content using preg_match_all.
I wrote a simple function to get list of functions in a file.
https://gist.github.com/komputronika/f92397b4f60870131ef52930faf09983
$a = functions_in_file( "mylib.php" );
The simplest thing (after I saw #joachim answer) is to use get_defined_functions and then only watch for the 'user' key (which contains an array of user-defined methods)
This is the code that helped me solved the problem
<?php
//Just to be sure it's empty (as it should be)
$functions = get_defined_functions();
print_r($functions['user']);
//Load the needed file
require_once '/path/to/your/file.php';
//display the functions loaded
$functions2 = get_defined_functions();
print_r($functions2['user']);
To retrieve also the params definition: (Source in comments)
Array
(
[0] => function foo ( &&bar, &big, [$small = 1] )
[1] => function bar ( &foo )
[2] => function noparams ( )
[3] => function byrefandopt ( [&$the = one] )
)
$functions = get_defined_functions();
$functions_list = array();
foreach ($functions['user'] as $func) {
$f = new ReflectionFunction($func);
$args = array();
foreach ($f->getParameters() as $param) {
$tmparg = '';
if ($param->isPassedByReference()) $tmparg = '&';
if ($param->isOptional()) {
$tmparg = '[' . $tmparg . '$' . $param->getName() . ' = ' . $param->getDefaultValue() . ']';
} else {
$tmparg.= '&' . $param->getName();
}
$args[] = $tmparg;
unset ($tmparg);
}
$functions_list[] = 'function ' . $func . ' ( ' . implode(', ', $args) . ' )' . PHP_EOL;
}
print_r($functions_list);
do include to the file and try this :
$functions = get_defined_functions();
print_r($functions['user']);