python to php code conversion - php

I have to translate two Python functions into PHP. The first one is:
def listspaces(string):
return [i -1 for i in range(len(string)) if string.startswith(' ', i-1)]
I am assuming that this will check for space in provided string and return True when first occurrence of space is found, is this correct ?
What is i-1 here ? is it -1 ?
In PHP we use [] for arrays . Here we are [] with return, will this function return true or false or array of locations of spaces ?
Second function is
def trimcopy(copy, spaces, length=350):
try:
if len(copy) < length:
return copy
else:
loc = 0
for space in spaces:
if space < length:
loc = space
else:
return copy[:loc]
except :
return None
Whats for space in spaces: here and whats is this return copy[:loc]

I think a good process for these type of conversions is:
work out what the code is doing
refactor it into a PHP-style in Python (this enables you to check that the logic still works, e.g. using assertion tests). e.g. convert list comprehensions to for loops
convert to PHP
For example, listspaces(string) returns the positions of spaces in string, and although using a list comprehension is Pythonic, it's not very "PHP-onic".
def listspaces2(string): #PHP-onic listspaces
space_positions = []
for i in range(len(string))]:
if string[i] == ' ':
space_positions.append(i)
return space_positions
The second example, trimcopy is rather trickier (since the try, except may purposefully be catching some expected - to the writer (!) - exceptions - two possibles are string not having a len and spaces containing values longer than len(copy)), but it's hard to say so it's a good idea to refactor in Python and test.
You can do array slicing in PHP like copy[:loc] using array_slice($copy, 0, $loc);.
Note: usually in Python we would state explicitly which exception we are defending against (as opposed to Pokemon exception handling).

You may notice that the first function could also have been written as
def listspaces(str):
return [i for i, c in enumerate(str) if c==' ']
That version has the following straightforward conversion to PHP:
function listspaces($str) {
$spaces = array();
foreach (str_split($str) as $i => $chr)
if ($chr == ' ') $spaces[] = $i;
return $spaces;
}
As for the other function, this seems to do the same thing in very nearly the same idiom:
function trimcopy($copy, $spaces, $length=350) {
if (strlen($copy) < $length) {
return $copy;
} else {
foreach ($spaces as $space) {
if ($space < $length) {
$loc = $space;
} else {
return substr($copy, 0, $loc);
}
}
}
}
As others have pointed out, the intent of both of these functions could probably be better expressed by using wordwrap.

Why don't you just test those functions to see what they are doing?
listspaces(string) returns an array with the positions of all spaces within the string:
$ ipython
IPython 0.10.2 -- An enhanced Interactive Python.
In [1]: def listspaces(string):
...: return [i -1 for i in range(len(string)) if string.startswith(' ', i-1)]
...:
In [2]: listspaces('Hallo du schöne neue Welt!')
Out[2]: [5, 8, 16, 21]
(i -1 is the position of a space when starting to count with zero)
I don't know much about Python and I can't paste the second function as there are to many "IndentationError"'s.
I think that trimcopy() will return a string (from input copy), where everything behind the last space position given in the array spaces (obviously a return value from listspaces()) is trimmed, unless the input is no longer than length.
In other words: the input is cut off at the highest space position that is smaller than length.
As of the example above, the part ' Welt!' will get cut off:
s = 'Hallo du schöne neue Welt!'
trimcopy( s, listspaces( s ) )
/* should return: 'Hallo du schöne neue' */

The first function returns indexes of all spaces in given string.
range(len(string)) results in list with numbers from 0 to length of the input string
if string.startswith(' ', i-1)] condition is evaluated for each index i, it returns true when string (here it is not a keyword) starts with ' ' at position given by the index i-1
The result is as feela posted.
For the second function I don't know what the spaces parameter is.
Hope this will help you to create a PHP version.

This is equivalent to both the functions in Python
list($short) = explode("\n",wordwrap($string,350));

Related

how to output INT values with proper commas from a mysql table? [duplicate]

I am trying to print an integer in JavaScript with commas as thousands separators. For example, I want to show the number 1234567 as "1,234,567". How would I go about doing this?
Here is how I am doing it:
function numberWithCommas(x) {
x = x.toString();
var pattern = /(-?\d+)(\d{3})/;
while (pattern.test(x))
x = x.replace(pattern, "$1,$2");
return x;
}
console.log(numberWithCommas(1000))
Is there a simpler or more elegant way to do it? It would be nice if it works with floats also, but that is not necessary. It does not need to be locale-specific to decide between periods and commas.
I used the idea from Kerry's answer, but simplified it since I was just looking for something simple for my specific purpose. Here is what I have:
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}
function test(x, expect) {
const result = numberWithCommas(x);
const pass = result === expect;
console.log(`${pass ? "✓" : "ERROR ====>"} ${x} => ${result}`);
return pass;
}
let failures = 0;
failures += !test(0, "0");
failures += !test(100, "100");
failures += !test(1000, "1,000");
failures += !test(10000, "10,000");
failures += !test(100000, "100,000");
failures += !test(1000000, "1,000,000");
failures += !test(10000000, "10,000,000");
if (failures) {
console.log(`${failures} test(s) failed`);
} else {
console.log("All tests passed");
}
.as-console-wrapper {
max-height: 100% !important;
}
The regex uses 2 lookahead assertions:
a positive one to look for any point in the string that has a multiple of 3 digits in a row after it,
a negative assertion to make sure that point only has exactly a multiple of 3 digits. The replacement expression puts a comma there.
For example, if you pass it 123456789.01, the positive assertion will match every spot to the left of the 7 (since 789 is a multiple of 3 digits, 678 is a multiple of 3 digits, 567, etc.). The negative assertion checks that the multiple of 3 digits does not have any digits after it. 789 has a period after it so it is exactly a multiple of 3 digits, so a comma goes there. 678 is a multiple of 3 digits but it has a 9 after it, so those 3 digits are part of a group of 4, and a comma does not go there. Similarly for 567. 456789 is 6 digits, which is a multiple of 3, so a comma goes before that. 345678 is a multiple of 3, but it has a 9 after it, so no comma goes there. And so on. The \B keeps the regex from putting a comma at the beginning of the string.
#neu-rah mentioned that this function adds commas in undesirable places if there are more than 3 digits after the decimal point. If this is a problem, you can use this function:
function numberWithCommas(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
function numberWithCommas(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
function test(x, expect) {
const result = numberWithCommas(x);
const pass = result === expect;
console.log(`${pass ? "✓" : "ERROR ====>"} ${x} => ${result}`);
return pass;
}
let failures = 0;
failures += !test(0 , "0");
failures += !test(0.123456 , "0.123456");
failures += !test(100 , "100");
failures += !test(100.123456 , "100.123456");
failures += !test(1000 , "1,000");
failures += !test(1000.123456 , "1,000.123456");
failures += !test(10000 , "10,000");
failures += !test(10000.123456 , "10,000.123456");
failures += !test(100000 , "100,000");
failures += !test(100000.123456 , "100,000.123456");
failures += !test(1000000 , "1,000,000");
failures += !test(1000000.123456 , "1,000,000.123456");
failures += !test(10000000 , "10,000,000");
failures += !test(10000000.123456, "10,000,000.123456");
if (failures) {
console.log(`${failures} test(s) failed`);
} else {
console.log("All tests passed");
}
.as-console-wrapper {
max-height: 100% !important;
}
#t.j.crowder pointed out that now that JavaScript has lookbehind (support info), it can be solved in the regular expression itself:
function numberWithCommas(x) {
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}
function test(x, expect) {
const result = numberWithCommas(x);
const pass = result === expect;
console.log(`${pass ? "✓" : "ERROR ====>"} ${x} => ${result}`);
return pass;
}
let failures = 0;
failures += !test(0, "0");
failures += !test(0.123456, "0.123456");
failures += !test(100, "100");
failures += !test(100.123456, "100.123456");
failures += !test(1000, "1,000");
failures += !test(1000.123456, "1,000.123456");
failures += !test(10000, "10,000");
failures += !test(10000.123456, "10,000.123456");
failures += !test(100000, "100,000");
failures += !test(100000.123456, "100,000.123456");
failures += !test(1000000, "1,000,000");
failures += !test(1000000.123456, "1,000,000.123456");
failures += !test(10000000, "10,000,000");
failures += !test(10000000.123456, "10,000,000.123456");
if (failures) {
console.log(`${failures} test(s) failed`);
} else {
console.log("All tests passed");
}
.as-console-wrapper {
max-height: 100% !important;
}
(?<!\.\d*) is a negative lookbehind that says the match can't be preceded by a . followed by zero or more digits. The negative lookbehind is faster than the split and join solution (comparison), at least in V8.
I'm surprised nobody mentioned Number.prototype.toLocaleString.
It's implemented in JavaScript 1.5 (which was introduced in 1999) so it's basically supported across all major browsers.
var n = 34523453.345;
console.log(n.toLocaleString()); // "34,523,453.345"
It also works in Node.js as of v0.12 via inclusion of Intl
If you want something different, Numeral.js might be interesting.
Below are two different browser APIs that can transform Numbers into structured Strings. Keep in mind that not all users' machines have a locale that uses commas in numbers. To enforce commas to the output, any "western" locale may be used, such as en-US
let number = 1234567890; // Example number to be converted
⚠️ Mind that javascript has a maximum integer value of 9007199254740991
toLocaleString
// default behaviour on a machine with a local that uses commas for numbers
let number = 1234567890;
number.toLocaleString(); // "1,234,567,890"
// With custom settings, forcing a "US" locale to guarantee commas in output
let number2 = 1234.56789; // floating point example
number2.toLocaleString('en-US', {maximumFractionDigits:2}); // "1,234.57"
//You can also force a minimum of 2 trailing digits
let number3 = 1.5;
number3.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2}); //"1.50"
NumberFormat
let number = 1234567890;
let nf = new Intl.NumberFormat('en-US');
nf.format(number); // "1,234,567,890"
From what I checked (Firefox at least) they are both more or less same regarding performance.
⚡ Live demo: https://codepen.io/vsync/pen/MWjdbgL?editors=1000
I suggest using phpjs.org 's number_format()
function number_format(number, decimals, dec_point, thousands_sep) {
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
toFixedFix = function (n, prec) {
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
var k = Math.pow(10, prec);
return Math.round(n * k) / k;
},
s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.');
if (s[0].length > 3) {
s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
UPDATE 02/13/14
People have been reporting this doesn't work as expected, so I did a JS Fiddle that includes automated tests.
Update 26/11/2017
Here's that fiddle as a Stack Snippet with slightly modified output:
function number_format(number, decimals, dec_point, thousands_sep) {
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
toFixedFix = function (n, prec) {
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
var k = Math.pow(10, prec);
return Math.round(n * k) / k;
},
s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.');
if (s[0].length > 3) {
s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
var exampleNumber = 1;
function test(expected, number, decimals, dec_point, thousands_sep)
{
var actual = number_format(number, decimals, dec_point, thousands_sep);
console.log(
'Test case ' + exampleNumber + ': ' +
'(decimals: ' + (typeof decimals === 'undefined' ? '(default)' : decimals) +
', dec_point: "' + (typeof dec_point === 'undefined' ? '(default)' : dec_point) + '"' +
', thousands_sep: "' + (typeof thousands_sep === 'undefined' ? '(default)' : thousands_sep) + '")'
);
console.log(' => ' + (actual === expected ? 'Passed' : 'FAILED') + ', got "' + actual + '", expected "' + expected + '".');
exampleNumber++;
}
test('1,235', 1234.56);
test('1 234,56', 1234.56, 2, ',', ' ');
test('1234.57', 1234.5678, 2, '.', '');
test('67,00', 67, 2, ',', '.');
test('1,000', 1000);
test('67.31', 67.311, 2);
test('1,000.6', 1000.55, 1);
test('67.000,00000', 67000, 5, ',', '.');
test('1', 0.9, 0);
test('1.20', '1.20', 2);
test('1.2000', '1.20', 4);
test('1.200', '1.2000', 3);
.as-console-wrapper {
max-height: 100% !important;
}
This is a variation of #mikez302's answer, but modified to support numbers with decimals (per #neu-rah's feedback that numberWithCommas(12345.6789) -> "12,345.6,789" instead of "12,345.6789"
function numberWithCommas(n) {
var parts=n.toString().split(".");
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
}
function formatNumber (num) {
return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
}
print(formatNumber(2665)); // 2,665
print(formatNumber(102665)); // 102,665
print(formatNumber(111102665)); // 111,102,665
Using Regular expression
function toCommas(value) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
console.log(toCommas(123456789)); // 123,456,789
console.log(toCommas(1234567890)); // 1,234,567,890
console.log(toCommas(1234)); // 1,234
Using toLocaleString()
var number = 123456.789;
// request a currency format
console.log(number.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' }));
// → 123.456,79 €
// the Japanese yen doesn't use a minor unit
console.log(number.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' }))
// → ¥123,457
// limit to three significant digits
console.log(number.toLocaleString('en-IN', { maximumSignificantDigits: 3 }));
// → 1,23,000
ref MDN:Number.prototype.toLocaleString()
Using Intl.NumberFormat()
var number = 123456.789;
console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(number));
// expected output: "123.456,79 €"
// the Japanese yen doesn't use a minor unit
console.log(new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }).format(number));
// expected output: "¥123,457"
// limit to three significant digits
console.log(new Intl.NumberFormat('en-IN', { maximumSignificantDigits: 3 }).format(number));
// expected output: "1,23,000"
ref Intl.NumberFormat
DEMO AT HERE
<script type="text/javascript">
// Using Regular expression
function toCommas(value) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function commas() {
var num1 = document.myform.number1.value;
// Using Regular expression
document.getElementById('result1').value = toCommas(parseInt(num1));
// Using toLocaleString()
document.getElementById('result2').value = parseInt(num1).toLocaleString('ja-JP', {
style: 'currency',
currency: 'JPY'
});
// Using Intl.NumberFormat()
document.getElementById('result3').value = new Intl.NumberFormat('ja-JP', {
style: 'currency',
currency: 'JPY'
}).format(num1);
}
</script>
<FORM NAME="myform">
<INPUT TYPE="text" NAME="number1" VALUE="123456789">
<br>
<INPUT TYPE="button" NAME="button" Value="=>" onClick="commas()">
<br>Using Regular expression
<br>
<INPUT TYPE="text" ID="result1" NAME="result1" VALUE="">
<br>Using toLocaleString()
<br>
<INPUT TYPE="text" ID="result2" NAME="result2" VALUE="">
<br>Using Intl.NumberFormat()
<br>
<INPUT TYPE="text" ID="result3" NAME="result3" VALUE="">
</FORM>
Performance
http://jsben.ch/sifRd
Intl.NumberFormat
Native JS function. Supported by IE11, Edge, latest Safari, Chrome, Firefox, Opera, Safari on iOS and Chrome on Android.
var number = 3500;
console.log(new Intl.NumberFormat().format(number));
// → '3,500' if in US English locale
I am quite impressed by the number of answers this question has got. I like the answer by uKolka:
n.toLocaleString()
But unfortunately, in some locales like Spanish, it does not work (IMHO) as expected for numbers below 10,000:
Number(1000).toLocaleString('ES-es')
Gives 1000 and not 1.000.
See toLocaleString not working on numbers less than 10000 in all browsers to know why.
So I had to use the answer by Elias Zamaria choosing the right thousands separator character:
n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))
This one works well as a one-liner for both locales that use , or . as the thousands separator and starts working from 1,000 in all cases.
Number(1000).toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))
Gives 1.000 with a Spanish locale context.
Should you want to have absolute control over the way a number is formatted, you may also try the following:
let number = 1234.567
let decimals = 2
let decpoint = '.' // Or Number(0.1).toLocaleString().substring(1, 2)
let thousand = ',' // Or Number(10000).toLocaleString().substring(2, 3)
let n = Math.abs(number).toFixed(decimals).split('.')
n[0] = n[0].split('').reverse().map((c, i, a) =>
i > 0 && i < a.length && i % 3 == 0 ? c + thousand : c
).reverse().join('')
let final = (Math.sign(number) < 0 ? '-' : '') + n.join(decpoint)
console.log(final)
Gives 1,234.57.
This one does not need a regular expression. It works by adjusting the number to the desired amount of decimals with toFixed first, then dividing it around the decimal point . if there is one. The left side is then turned into an array of digits which is reversed. Then a thousands separator is added every three digits from the start and the result reversed again. The final result is the union of the two parts. The sign of the input number is removed with Math.abs first and then put back if necessary.
It is not a one-liner but not much longer and easily turned into a function. Variables have been added for clarity, but those may be substituted by their desired values if known in advance. You may use the expressions that use toLocaleString as a way to find out the right characters for the decimal point and the thousands separator for the current locale (bear in mind that those require a more modern Javascript.)
Thanks to everyone for their replies. I have built off of some of the answers to make a more "one-size-fits-all" solution.
The first snippet adds a function that mimics PHP's number_format() to the Number prototype. If I am formatting a number, I usually want decimal places so the function takes in the number of decimal places to show. Some countries use commas as the decimal and decimals as the thousands separator so the function allows these separators to be set.
Number.prototype.numberFormat = function(decimals, dec_point, thousands_sep) {
dec_point = typeof dec_point !== 'undefined' ? dec_point : '.';
thousands_sep = typeof thousands_sep !== 'undefined' ? thousands_sep : ',';
var parts = this.toFixed(decimals).split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousands_sep);
return parts.join(dec_point);
}
You would use this as follows:
var foo = 5000;
console.log(foo.numberFormat(2)); // us format: 5,000.00
console.log(foo.numberFormat(2, ',', '.')); // european format: 5.000,00
I found that I often needed to get the number back for math operations, but parseFloat converts 5,000 to 5, simply taking the first sequence of integer values. So I created my own float conversion function and added it to the String prototype.
String.prototype.getFloat = function(dec_point, thousands_sep) {
dec_point = typeof dec_point !== 'undefined' ? dec_point : '.';
thousands_sep = typeof thousands_sep !== 'undefined' ? thousands_sep : ',';
var parts = this.split(dec_point);
var re = new RegExp("[" + thousands_sep + "]");
parts[0] = parts[0].replace(re, '');
return parseFloat(parts.join(dec_point));
}
Now you can use both functions as follows:
var foo = 5000;
var fooString = foo.numberFormat(2); // The string 5,000.00
var fooFloat = fooString.getFloat(); // The number 5000;
console.log((fooString.getFloat() + 1).numberFormat(2)); // The string 5,001.00
I think this is the shortest regular expression that does it:
/\B(?=(\d{3})+\b)/g
"123456".replace(/\B(?=(\d{3})+\b)/g, ",")
I checked it on a few numbers and it worked.
Number.prototype.toLocaleString() would have been awesome if it was provided natively by all browsers (Safari).
I checked all other answers but noone seemed to polyfill it. Here is a poc towards that, which is actually a combination of first two answers; if toLocaleString works it uses it, if it doesn't it uses a custom function.
var putThousandsSeparators;
putThousandsSeparators = function(value, sep) {
if (sep == null) {
sep = ',';
}
// check if it needs formatting
if (value.toString() === value.toLocaleString()) {
// split decimals
var parts = value.toString().split('.')
// format whole numbers
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, sep);
// put them back together
value = parts[1] ? parts.join('.') : parts[0];
} else {
value = value.toLocaleString();
}
return value;
};
alert(putThousandsSeparators(1234567.890));
The thousands separator can be inserted in an international-friendly manner using the browser's Intl object:
Intl.NumberFormat().format(1234);
// returns "1,234" if the user's locale is en_US, for example
See MDN's article on NumberFormat for more, you can specify locale behavior or default to the user's. This is a little more foolproof because it respects local differences; many countries use periods to separate digits while a comma denotes the decimals.
Intl.NumberFormat isn't available in all browsers yet, but it works in latest Chrome, Opera, & IE. Firefox's next release should support it. Webkit doesn't seem to have a timeline for implementation.
You can either use this procedure to format your currency needing.
var nf = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
nf.format(123456.789); // ‘$123,456.79’
For more info you can access this link.
https://www.justinmccandless.com/post/formatting-currency-in-javascript/
if you are dealing with currency values and formatting a lot then it might be worth to add tiny accounting.js which handles lot of edge cases and localization:
// Default usage:
accounting.formatMoney(12345678); // $12,345,678.00
// European formatting (custom symbol and separators), could also use options object as second param:
accounting.formatMoney(4999.99, "€", 2, ".", ","); // €4.999,99
// Negative values are formatted nicely, too:
accounting.formatMoney(-500000, "£ ", 0); // £ -500,000
// Simple `format` string allows control of symbol position [%v = value, %s = symbol]:
accounting.formatMoney(5318008, { symbol: "GBP", format: "%v %s" }); // 5,318,008.00 GBP
The following code uses char scan, so there's no regex.
function commafy( num){
var parts = (''+(num<0?-num:num)).split("."), s=parts[0], L, i=L= s.length, o='';
while(i--){ o = (i===0?'':((L-i)%3?'':','))
+s.charAt(i) +o }
return (num<0?'-':'') + o + (parts[1] ? '.' + parts[1] : '');
}
It shows promising performance: http://jsperf.com/number-formatting-with-commas/5
2015.4.26: Minor fix to resolve issue when num<0. See https://jsfiddle.net/runsun/p5tqqvs3/
Here's a simple function that inserts commas for thousand separators. It uses array functions rather than a RegEx.
/**
* Format a number as a string with commas separating the thousands.
* #param num - The number to be formatted (e.g. 10000)
* #return A string representing the formatted number (e.g. "10,000")
*/
var formatNumber = function(num) {
var array = num.toString().split('');
var index = -3;
while (array.length + index > 0) {
array.splice(index, 0, ',');
// Decrement by 4 since we just added another unit to the array.
index -= 4;
}
return array.join('');
};
CodeSandbox link with examples: https://codesandbox.io/s/p38k63w0vq
Use This code to handle currency format for india. Country code can be changed to handle other country currency.
let amount =350256.95
var formatter = new Intl.NumberFormat('en-IN', {
minimumFractionDigits: 2,
});
// Use it.
formatter.format(amount);
output:
3,50,256.95
You can also use the Intl.NumberFormat constructor. Here is how you can do it.
resultNumber = new Intl.NumberFormat('en-IN', { maximumSignificantDigits: 3 }).format(yourNumber);
Universal, fast, accurate, simple function
Using RegEx (Fast & Accurate)
Support Numbers(Float/Integer)/String/Multiple numbers in a string
Smart well (Not grouping decimals - Compatible with different types of grouping)
Support all browsers specially 'Safari' & 'IE' & many older browsers
[Optional] Respecting non-English (Persian/Arabic) digits (+ Pre-fix)
TL;DR - Full version function (minified):
// num: Number/s (String/Number),
// sep: Thousands separator (String) - Default: ','
// dec: Decimal separator (String) - Default: '.' (Just one char)
// u: Universal support for languages characters (String - RegEx character set / class) - Example: '[\\d\\u0660-\\u0669\\u06f0-\\u06f9]' (English/Persian/Arabic), Default: '\\d' (English)
function formatNums(num,sep,dec,u){sep=sep||',';u=u||'\\d';if(typeof num!='string'){num=String(num);if(dec&&dec!='.')num=num.replace('.',dec);}return num.replace(RegExp('\\'+(dec||'.')+u+'+|'+u+'(?=(?:'+u+'{3})+(?!'+u+'))','g'),function(a){return a.length==1?a+sep:a})}
text='100000000 English or Persian/Arabic ۱۲۳۴۵۶۷۸۹/٠١٢٣٤٥٦٧٨٩ this is 123123123.123123123 with this -123123 and these 10 100 1000 123123/123123 (2000000) .33333 100.00 or any like 500000Kg';
console.log(formatNums(10000000.0012));
console.log(formatNums(10000000.0012,'.',',')); // German
console.log(formatNums(text,',','.','[\\d\\u0660-\\u0669\\u06f0-\\u06f9]')); // Respect Persian/Arabic digits
<input oninput="document.getElementById('result').textContent=formatNums(this.value)" placeholder="Type a number here">
<div id="result"></div>
Why NOT satisfied with other answers?
Number.prototype.toLocaleString() / Intl.NumberFormat
(Right answer)
If no well arguments, we can't expect same result. Also with arguments options we still can't be sure what can be the result because it will use local settings and possible client modifications effect on it or the browser/device not support it.
>~2016 browsers support and still in 2021 some reports that in some cases like Safari or IE/Edge do not return as expected.
toLocaleString() Work with numbers, Intl.NumberFormat Work with String/Numbers; Strings will be/have to be parsed and also rounded if necessary, so:
If we already have a localized string with non-English digits we have to replace numbers with the English one, then parse it, then use it again with the local options. (If it return what we expect)
Generally while parsing we cant expect not missing decimal zeros or details in big numbers or respecting other languages numeral characters
Decimal / Thousand separator characters can not be customized more than language options, except with post-fixings with replace() + RegEx again. (For example in Persian usually we don't use the suggested Arabic comma and also sometime we use ∕ Fraction/Division slash as decimal separator)
Slow performance in loops
Not so good RegEx ways (Fastest & One-liner ways)
/\B(?=(\d{3})+\b)/ it will group decimals too. // 123,123.123,123 !!!
/(?<!\.\d+)\B(?=(\d{3})+\b)/ used look-behind that not supported well yet. Please check:
https://caniuse.com/js-regexp-lookbehind
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#browser_compatibility
Note: Generally lookbehind can be against of original RegEx structure (because of how the analyzer should work like do not buffer the raw behind as a parser) and actually it can make the performance seriously low (In this case ~30%). I think it pushed inside over the time by requests.
/\B(?=(?=\d*\.)(\d{3})+(?!\d))/ just work with float numbers and ignore integers.
.replace(/(?:[^.\d]|^)\d+/g,function(a){return a.replace(/\B(?=(?:\d{3})+\b)/g,',');}) (My old idea) Using 2 RegEx. First one find the integer parts, second one put separator. Why 2 functions, when it can be mixed?
/(\..*)$|(\d)(?=(\d{3})+(?!\d))/g (Good idea by #djulien - i voted up) but when the RegEx is global, (\..*)$ it can make a mistake even with a space in end.
Also using capturing groups (Example: (\d)) will make the performance low so if it possible, use non-capturing groups (Example: (?:\d)) or if an statement already exist in our function let's mix it.
In this case, not using capturing groups improve performance about ~20% and in case of /\B(?=(\d{3})+\b)/g vs /\B(?=(?:\d{3})+\b)/g, the second one is ~8% faster.
About regex performances:
Note: Sure different methods, browsers, hardware, system status, cases and even changes on ECMAScript will effect on result of checking performance. But some changes logically should effect result and i used this one just as visual example.
Using library's like Numeral.js so much not necessary functions for a simple task.
Heavy code / Not accurate functions that used .split('.') or .toFixed() or Math.floor() ...
Final result:
There is no best of all and it should be chosen based on the need. My priority of sorting;
Compatibility
Capability
Universality
Ease of use
Performance
toLocaleString() (Compatibility - Universality) [Native function]
If you have to change digits and grouping from English to another language
If you are not sure about your client language
If you don't need to have exact expected result
If you don't care about older version of Safari
// 1000000.2301
parseFloat(num) // (Pre-fix) If the input is string
.toLocaleString('en-US', {
useGrouping: true // (Default is true, here is just for show)
});
// 1,000,000.23
Read more: https://www.w3schools.com/jsref/jsref_tolocalestring_number.asp
Intl.NumberFormat() (Capability - Universality - Compatibility) [Native function]
Almost same as toLocaleString() +
Great capability of supporting currency, units, etc... any language (Modern browsers)
// 1000000.2301
new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
numberingSystem: 'arab'
}).format(num)
// ١٬٠٠٠٬٠٠٠٫٢٣
Read more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
With these much options of the native functions, we still can not expect:
Exact result (+ Not parsing the input / Not rounding / Not converting big numbers)
Accepting other languages digits as input
Customizing separators
Trusting browsers support
Performance
So you maybe need a function like any of these:
formatNums() (Compatibility - Ease of use)
Full version (Capability) (Not faster than toLocaleString) - Explain:
function formatNums(num, sep, dec, u) {
// Setting defaults
sep = sep || ','; // Seperator
u = u || '\\d'; // Universal character set \d: 0-9 (English)
// Mixing of Handeling numbers when the decimal character should be changed + Being sure the input is string
if (typeof num != 'string') {
num = String(num);
if (dec && dec != '.') num = num.replace('.', dec); // Replacing sure decimal character with the custom
}
//
return num.replace(RegExp('\\' + (dec || '.') + u + '+|' + u + '(?=(?:' + u + '{3})+(?!' + u + '))', 'g'),
// The RegEx will be like /\.\d+|\d(?=(?:\d{3})+(?!\d))/g if not be customized
// RegEx explain:
// 1) \.\d+ : First try to get any part that started with a dot and followed by any much of English digits, one or more (For ignoring it later)
// 2) | : Or
// 3) \d : Get any 1 char digit
// 3.1) (?=...) : That the next of that should be
// 3.2) (?:\d{3}) : 3 length digits
// 3.2.1) + : One or more of the group
// 3.3) (?!\d) : ...till any place that there is no digits
function(a) { // Any match can be the decimal part or the integer part so lets check it
return a.length == 1 ? a + sep : a // If the match is one character, it is from the grouping part as item (3) in Regex explain so add the seperator next of it, if not, ignore it and return it back.
})
}
function formatNums(num,sep,dec,u) {
sep=sep||',';
u=u||'\\d';
if(typeof num!='string') {
num=String(num);
if( dec && dec!='.') num=num.replace('.',dec);
}
return num.replace(RegExp('\\'+(dec||'.')+u+'+|'+u+'(?=(?:'+u+'{3})+(?!'+u+'))','g'),function(a) {return a.length==1 ? a+sep : a})
}
console.log(formatNums(1000000.2301));
console.log(formatNums(100.2301));
console.log(formatNums(-2000.2301));
console.log(formatNums(123123123,' , '));
console.log(formatNums('0000.0000'));
console.log(formatNums('5000000.00'));
console.log(formatNums('5000000,00',' ',','));
console.log(formatNums(5000000.1234,' ',','));
console.log(formatNums('۱۲۳۴۵۶۷۸۹/۹۰۰۰',',','/','[\\d\\u0660-\\u0669\\u06f0-\\u06f9]'));
Play with the examples here:
https://jsfiddle.net/PAPIONbit/198xL3te/
Light version (Performance) (~30% faster than toLocaleString)
function formatNums(num,sep) {
sep=sep||',';
return String(num).replace(/\.\d+|\d(?=(?:\d{3})+(?!\d))/g,
function(a) {
return a.length==1?a+sep:a
}
);
}
console.log(formatNums(1000000.2301));
console.log(formatNums(100.2301));
console.log(formatNums(-2000.2301));
console.log(formatNums(123123123,' '));
Check the RegEx (Without the necessary function) : https://regexr.com/66ott
(num+'').replace(/\B(?=(?:\d{3})+\b)/g,','); (Performance - Compatibility)
Best choose if The input is Specified / Predefined. (Like usual prices that sure will not have more than 3 decimals)
(~65% faster than toLocaleString)
num=1000000;
str='123123.100';
console.log((num+'').replace(/\B(?=(?:\d{3})+\b)/g,','));
console.log(str.replace(/\B(?=(?:\d{3})+\b)/g,','));
+
For Persian/Arabic local clients:
If your client going to use Persian/Arabic numbers for input as what is usual in Iran, I think the best way is instead of keeping the original characters, convert them to English before you deal with, to you can calculate it.
// ۱۲۳۴۵۶۷۸۹۰
function toEnNum(n) { // Replacing Persian/Arabic numbers character with English
n.replace(/[\u0660-\u0669\u06f0-\u06f9]/g, // RegEx unicode range Persian/Arabic numbers char
function(c) {
return c.charCodeAt(0) & 0xf; // Replace the char with real number by getting the binary index and breaking to lowest using 15
}
);
}
// 1234567890
And for still showing them as original looking there is 2 ways:
CSS Using Persian/Arabic fonts with local digits (My choose)
Convert the result back with Intl.NumberFormat or a function like: https://stackoverflow.com/a/13787021/7514010
My Old-school function on this post: (~15% Faster than toLocalString)
// 10000000.0012
function formatNums(n, s) {
return s = s || ",", String(n).
replace(/(?:^|[^.\d])\d+/g, // First this RegEx take just integer parts
function(n) {
return n.replace(/\B(?=(?:\d{3})+\b)/g, s);
})
}
// 10,000,000.0012
var formatNumber = function (number) {
var splitNum;
number = Math.abs(number);
number = number.toFixed(2);
splitNum = number.split('.');
splitNum[0] = splitNum[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return splitNum.join(".");
}
EDIT:
The function only work with positive number. for exmaple:
var number = -123123231232;
formatNumber(number)
Output: "123,123,231,232"
But to answer the question above toLocaleString() method just solves the problem.
var number = 123123231232;
number.toLocaleString()
Output: "123,123,231,232"
Cheer!
My answer is the only answer that completely replaces jQuery with a much more sensible alternative:
function $(dollarAmount)
{
const locale = 'en-US';
const options = { style: 'currency', currency: 'USD' };
return Intl.NumberFormat(locale, options).format(dollarAmount);
}
This solution not only adds commas, but it also rounds to the nearest penny in the event that you input an amount like $(1000.9999) you'll get $1,001.00. Additionally, the value you input can safely be a number or a string; it doesn't matter.
If you're dealing with money, but don't want a leading dollar sign shown on the amount, you can also add this function, which uses the previous function but removes the $:
function no$(dollarAmount)
{
return $(dollarAmount).replace('$','');
}
If you're not dealing with money, and have varying decimal formatting requirements, here's a more versatile function:
function addCommas(number, minDecimalPlaces = 0, maxDecimalPlaces = Math.max(3,minDecimalPlaces))
{
const options = {};
options.maximumFractionDigits = maxDecimalPlaces;
options.minimumFractionDigits = minDecimalPlaces;
return Intl.NumberFormat('en-US',options).format(number);
}
Oh, and by the way, the fact that this code does not work in some old version of Internet Explorer is completely intentional. I try to break IE anytime that I can catch it not supporting modern standards.
Please remember that excessive praise, in the comment section, is considered off-topic. Instead, just shower me with up-votes.
I Wrote this one before stumbling on this post. No regex and you can actually understand the code.
$(function(){
function insertCommas(s) {
// get stuff before the dot
var d = s.indexOf('.');
var s2 = d === -1 ? s : s.slice(0, d);
// insert commas every 3 digits from the right
for (var i = s2.length - 3; i > 0; i -= 3)
s2 = s2.slice(0, i) + ',' + s2.slice(i);
// append fractional part
if (d !== -1)
s2 += s.slice(d);
return s2;
}
$('#theDudeAbides').text( insertCommas('1234567.89012' ) );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="theDudeAbides"></div>
For anyone who likes 1-liners and a single regex, but doesn't want to use split(), here is an enhanced version of the regex from other answers that handles (ignores) decimal places:
var formatted = (x+'').replace(/(\..*)$|(\d)(?=(\d{3})+(?!\d))/g, (digit, fract) => fract || digit + ',');
The regex first matches a substring starting with a literal "." and replaces it with itself ("fract"), and then matches any digit followed by multiples of 3 digits and puts "," after it.
For example, x = 12345678.12345678 will give formatted = '12,345,678.12345678'.
Let me try to improve uKolka's answer and maybe help others save some time.
Use Numeral.js.
document.body.textContent = numeral(1234567).format('0,0');
<script src="//cdnjs.cloudflare.com/ajax/libs/numeral.js/1.4.5/numeral.min.js"></script>
You should go with Number.prototype.toLocaleString() only if its browser compatibilty is not an issue.
Just for future Googlers (or not necessarily 'Googlers'):
All of solutions mentioned above are wonderful, however, RegExp might be awfully bad thing to use in a situation like that.
So, yes, you might use some of the options proposed or even write something primitive yet useful like:
const strToNum = str => {
//Find 1-3 digits followed by exactly 3 digits & a comma or end of string
let regx = /(\d{1,3})(\d{3}(?:,|$))/;
let currStr;
do {
currStr = (currStr || str.split(`.`)[0])
.replace( regx, `$1,$2`)
} while (currStr.match(regx)) //Stop when there's no match & null's returned
return ( str.split(`.`)[1] ) ?
currStr.concat(`.`, str.split(`.`)[1]) :
currStr;
};
strToNum(`123`) // => 123
strToNum(`123456`) // => 123,456
strToNum(`-1234567.0987`) // => -1,234,567.0987
The regexp that's used here is fairly simple and the loop will go precisely the number of times it takes to get the job done.
And you might optimize it far better, "DRYify" code & so on.
Yet,
(-1234567.0987).toLocaleString();
(in most situations) would be a far better choice.
The point is not in the speed of execution or in cross-browser compatibility.
In situations when you'd like to show the resulting number to user, .toLocaleString() method gives you superpower to speak the same language with the user of your website or app (whatever her/his language is).
This method according to ECMAScript documentation was introduced in 1999, and I believe that the reason for that was the hope that the Internet at some point will connect people all around the world, so, some "internalization" tools were needed.
Today the Internet does connect all of us, so, it is important to remember that the world is a way more complex that we might imagine & that (/almost) all of us are here, in the Internet.
Obviously, considering the diversity of people, it is impossible to guarantee perfect UX for everybody because we speak different languages, value different things, etc. And exactly because of this, it is even more important to try to localize things as much as it's possible.
So, considering that there're some particular standards for representation of date, time, numbers, etc. & that we have a tool to display those things in the format preferred by the final user, isn't that rare and almost irresponsible not to use that tool (especially in situations when we want to display this data to the user)?
For me, using RegExp instead of .toLocaleString() in situation like that sounds a little bit like creating a clock app with JavaScript & hard-coding it in such a way so it'll display Prague time only (which would be quite useless for people who don't live in Prague) even though the default behaviour of
new Date();
is to return the data according to final user's clock.
An alternative way, supporting decimals, different separators and negatives.
var number_format = function(number, decimal_pos, decimal_sep, thousand_sep) {
var ts = ( thousand_sep == null ? ',' : thousand_sep )
, ds = ( decimal_sep == null ? '.' : decimal_sep )
, dp = ( decimal_pos == null ? 2 : decimal_pos )
, n = Math.floor(Math.abs(number)).toString()
, i = n.length % 3
, f = ((number < 0) ? '-' : '') + n.substr(0, i)
;
for(;i<n.length;i+=3) {
if(i!=0) f+=ts;
f+=n.substr(i,3);
}
if(dp > 0)
f += ds + parseFloat(number).toFixed(dp).split('.')[1]
return f;
}
Some corrections by #Jignesh Sanghani, don't forget to upvote his comment.
I think this function will take care of all the issues related to this problem.
function commaFormat(inputString) {
inputString = inputString.toString();
var decimalPart = "";
if (inputString.indexOf('.') != -1) {
//alert("decimal number");
inputString = inputString.split(".");
decimalPart = "." + inputString[1];
inputString = inputString[0];
//alert(inputString);
//alert(decimalPart);
}
var outputString = "";
var count = 0;
for (var i = inputString.length - 1; i >= 0 && inputString.charAt(i) != '-'; i--) {
//alert("inside for" + inputString.charAt(i) + "and count=" + count + " and outputString=" + outputString);
if (count == 3) {
outputString += ",";
count = 0;
}
outputString += inputString.charAt(i);
count++;
}
if (inputString.charAt(0) == '-') {
outputString += "-";
}
//alert(outputString);
//alert(outputString.split("").reverse().join(""));
return outputString.split("").reverse().join("") + decimalPart;
}
If you're looking for a short and sweet solution:
const number = 12345678.99;
const numberString = String(number).replace(
/^\d+/,
number => [...number].map(
(digit, index, digits) => (
!index || (digits.length - index) % 3 ? '' : ','
) + digit
).join('')
);
// numberString: 12,345,678.99
I think your solution is one of the shorter ones I've seen for this. I don't think there are any standard JavaScript functions to do this sort of thing, so you're probably on your own.
I checked the CSS 3 specifications to see whether it's possible to do this in CSS, but unless you want every digit in its own <span>, I don't think that's possible.
I did find one project on Google Code that looked promising: flexible-js-formatting. I haven't used it, but it looks pretty flexible and has unit tests using JsUnit. The developer also has a lot of posts (though old) about this topic.
Be sure to consider international users: lots of nations use a space as the separator and use the comma for separating the decimal from the integral part of the number.

Split strings into Dictionary words

I am looking for the most efficient algorithm in PHP to check if a string was made from dictionary words only or not.
Example:
thissentencewasmadefromenglishwords
thisonecontainsyxxxyxsomegarbagexaatoo
pure
thisisalsobadxyyyaazzz
Output:
thissentencewasmadefromenglishwords
pure
a.txt
contains the dictionary words
b.txt
contains the strings: one in every line, without spaces made from a..z chars only
Another way to do this is to employ the Aho-Corasick string matching algorithm. The basic idea is to read in your dictionary of words and from that create the Aho-Corasick tree structure. Then, you run each string you want to split into words through the search function.
The beauty of this approach is that creating the tree is a one time cost. You can then use it for all of the strings you're testing. The search function runs in O(n) (n being the length of the string), plus the number of matches found. It's really quite efficient.
Output from the search function will be a list of string matches, telling you which words match at what positions.
The Wikipedia article does not give a great explanation of the Aho-Corasick algorithm. I prefer the original paper, which is quite approachable. See Efficient String Matching: An Aid to Bibliographic Search.
So, for example, given your first string:
thissentencewasmadefromenglishwords
You would get (in part):
this, 0
his, 1
sent, 4
ten, 7
etc.
Now, sort the list of matches by position. It will be almost sorted when you get it from the string matcher, but not quite.
Once the list is sorted by position, the first thing you do is make sure that there is a match at position 0. If there is not, then the string fails the test. If there is (and there might be multiple matches at position 0), you take the length of the matched string and see if there's a string match at that position. Add that match's length and see if there's a match at the next position, etc.
If the strings you're testing aren't very long, then you can use a brute force algorithm like that. It would be more efficient, though, to construct a hash map of the matches, indexed by position. Of course, there could be multiple matches for a particular position, so you have to take that into account. But looking to see if there is a match at a position would be very fast.
It's some work, of course, to implement the Aho-Corasick algorithm. A quick Google search shows that there are php implementations available. How well they work, I don't know.
In the average case, this should be very quick. Again, it depends on how long your strings are. But you're helped by there being relatively few matches at any one position. You could probably construct strings that would exhibit pathologically poor runtimes, but you'd probably have to try real hard. And again, even a pathological case isn't going to take too terribly long if the string is short.
This is a problem that can be solved using Dynamic Programming, based on the next formulas:
f(0) = true
f(i) = OR { f(i-j) AND Dictionary.contais(s.substring(i-j,i) } for each j=1,...,i
First, load your file into a dictionary, then use the DP solution for the above formula.
Pseudo code is something like: (Hope I have no "off by one" for indices..)
check(word):
f = new boolean[word.length() + 1)
f[0] = true
for i from 1 to word.length() + 1:
f[i] = false
for j from 1 to i-1:
if dictionary.contains(word.substring(j-1,i-1)) AND f[j]:
f[i] = true
return f[word.length()
I recommend a recursive approach. Something like this:
<?php
$wordsToCheck = array(
'otherword',
'word1andother',
'word1',
'word1word2',
'word1word3',
'word1word2word3'
);
$wordList = array(
'word1',
'word2',
'word3'
);
$results = array();
function onlyListedWords($word, $wordList) {
if (in_array($word, $wordList)) {
return true;
} else {
$length = strlen($word);
$wordTemp = $word;
$part = '';
for ($i=0; $i < $length; $i++) {
$part .= $wordTemp[$i];
if (in_array($part, $wordList)) {
if ($i == $length - 1) {
return true;
} else {
$wordTemp = substr($wordTemp, $i + 1);
return onlyListedWords($wordTemp, $wordList);
}
}
}
}
}
foreach ($wordsToCheck as $word) {
if (onlyListedWords($word, $wordList))
$results[] = $word;
}
var_dump($results);
?>

Unidentified Error in Program: Unfriendly Numbers

There is a problem in Interview Street challange. Maybe the most easiest of all challenges. "Unfriendly Numbers", is the name and question goes like this.
There is one friendly number and N unfriendly numbers. We want to find how many numbers are there which exactly divide the friendly number, but does not divide any of the unfriendly numbers.
Input Format:
The first line of input contains two numbers N and K seperated by spaces. N is the number of unfriendly numbers, K is the friendly number.
The second line of input contains N space separated unfriendly numbers.
Output Format:
Output the answer in a single line.
I did a PHP programming like this:
<?php
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
$handle = fopen ("php://stdin","r");
$input = fgets($handle);
$num_unfriendly_number=substr($input,0,1);
$friendly_number=substr($input,2,1);
$input2=fgets($handle);
for($i=0;$i<=($num_unfriendly_number); $i=$i+2){
$unfriendly_numbers[$i]=substr($input2,$i,1);
}
//truncates additional input
//now getting divisiors of given friendly numbers
$check_num=1;
//one is always a divisor of any number
$divisior[0]=1;
$arrayindex=1;
for($check_num; $check_num<=$friendly_number; $check_num++){
$hold_var=$friendly_number%$check_num;
if($hold_var==0){
$divisor[$arrayindex]=$check_num;
$arrayindex++;
}
}
$index=0;
foreach($divisor as $test_div){
$output=true;
foreach($unfriendly_numbers as $test_unfrnd){
if($test_unfrnd%$test_div){
$output=false;
}
}
if ($output){
$outputarray[$index]=$test_div;
$index++; //edited afterwards after #Boris's suggestion but didn't work :(
}
}
$num_of_output=count($outputarray);
define('STDOUT',fopen("php://stout","r"));
fwrite(STDOUT,$num_of_output);
?>
The above programme worked fine for 2 testcases but did not applied for other tests. I did some research but did not found any errors. Any helps please. Thanks in advance.
Fist of all I would like to mention that I do not know php. However, I think this is simple enough I can try to help.
Several errors I see:
for($i=0;$i<=($num_unfriendly_number); $i=$i+2){
$unfriendly_numbers[$i]=substr($input2,$i,1);
}
Here you use substr($input2,$i,1);, this however assumes all your unfriendly numbers are digits, which might not always be the case. Better use the split function in php. Replace the whole while with the following:
$unfriendly_numbers = explode(" ", $input2);
After that:
$index=0;
foreach($divisor as $test_div){
$output=true;
foreach($unfriendly_numbers as $test_unfrnd){
if($test_unfrnd%$test_div){
$output=false;
}
}
if ($output){
$outputarray[$index]=$test_div;
}
}
Here you never increase the $index variable. Isn't this meaning that you will override the divisors one with other? USe the operator []=. It appends to an array in php:
if ($output){
$outputarray []= $test_div;
}
EDIT One more error I see is that you count on the friendly number to be a digit too. You can fix this too:
$friendly_number=substr($input,2,1);
->
$friendly_number=explode(" ", $input)[0];
I have the same problem I can't understand why this code can't finish in less than 16 seconds!
I would like to hear your tricks
a = raw_input()# this will read this line: 8 16
b = raw_input()# this will read this line: 2 5 7 4 3 8 3 18
al = a.split()
bl = b.split()
blint = []
fn = int(al[1])
fnlist = [fn]
half_fn = fn / 2 # only I go to half the number to save some time
k = 1
while k <= half_fn:
if fn % k == 0:
fnlist.append(k)
k += 1
plist = []
for j in bl:
blint.append(int(j)) # here I changed the bl list elements which are string to int
for i in fnlist:
for j in blint: #I have the int elements so I don't need every time bring the string and change it to int
if j % i == 0:
plist.append(i)
break
counter = len(fnlist) - len(plist)
print counter

How to convert some character into numeric in php?

I need help to change a character in php.
I got some code from the web:
char dest='a';
int conv=(int)dest;
Can I use this code to convert a character into numeric? Or do you have any ideas?
I just want to show the result as a decimal number:
if null == 0
if A == 1
Use ord() to return the ascii value. Subtract 96 to return a number where a=1, b=2....
Upper and lower case letters have different ASCII values, so if you want to handle them the same, you can use strtolower() to convert upper case to lower case.
To handle the NULL case, simply use if($dest). This will be true if $dest is something other than NULL or 0.
PHP is a loosely typed language, so there is no need to declare the types. So char dest='a'; is incorrect. Variables have $ prefix in PHP and no type declaration, so it should be $dest = 'a';.
Live Example
<?php
function toNumber($dest)
{
if ($dest)
return ord(strtolower($dest)) - 96;
else
return 0;
}
// Let's test the function...
echo toNumber(NULL) . " ";
echo toNumber('a') . " ";
echo toNumber('B') . " ";
echo toNumber('c');
// Output is:
// 0 1 2 3
?>
PS:
You can look at the ASCII values here.
It does indeed work as in the sample, except that you should be using php syntax (and as a sidenote: the language that code you found most probably was, it did not do the same thing).
So:
$in = "123";
$out = (int)$in;
Afterwards the following will be true:
$out === 123
This may help you:
http://www.php.net/manual/en/function.ord.php
So, if you need the ASCII code you will need to do:
$dest = 'a';
$conv = ord($dest);
If you want something like:
a == 1
b == 2
.
.
.
you should do:
$dest = 'a';
$conv = ord($dest)-96;
For more info on the ASCII codes: http://www.asciitable.com/
And for the function ord: http://www.php.net/manual/en/function.ord.php
It's very hard to answer because it's not a real question but just a little bit of it.
But if you ask.
It seems you need some translation table, that defines links between letters and numbers
A -> 2
B -> 3
C -> 4
S -> 1
or whatever.
You can achieve this by using an array, where keys would be these letters and values - desired numbers.
$defects_arr = array(
'A' -> 2,
'B' -> 3,
'C' -> 4'
'S' -> 1
};
Thus, you can convert these letters to numbers
$letter = 'A';
$number = $defects_arr($letter);
echo $number; // outputs 1
But it still seems is not what you want.
Do these defect types have any verbose equivalents? If so, why not to use them instead of letters?
Telling the whole story instead of little bit of it will help you to avoid mistakes and will save a ton of time, both yours and those who to answer.
Out of this question, if you are looking for convert RT0005 to 5
$max = 'RT0005';
return base_convert($max,10,10);
// return 5

Whats the cleanest way to convert a 5-7 digit number into xxx/xxx/xxx format in php?

I have sets of 5, 6 and 7 digit numbers. I need them to be displayed in the 000/000/000 format. So for example:
12345 would be displayed as 000/012/345
and
9876543 would be displayed as 009/876/543
I know how to do this in a messy way, involving a series of if/else statements, and strlen functions, but there has to be a cleaner way involving regex that Im not seeing.
sprintf and modulo is one option
function formatMyNumber($num)
{
return sprintf('%03d/%03d/%03d',
$num / 1000000,
($num / 1000) % 1000,
$num % 1000);
}
$padded = str_pad($number, 9, '0', STR_PAD_LEFT);
$split = str_split($padded, 3);
$formatted = implode('/', $split);
You asked for a regex solution, and I love playing with them, so here is a regex solution!
I show it for educational (and fun) purpose only, just use Adam's solution, clean, readable and fast.
function FormatWithSlashes($number)
{
return substr(preg_replace('/(\d{3})?(\d{3})?(\d{3})$/', '$1/$2/$3',
'0000' . $number),
-11, 11);
}
$numbers = Array(12345, 345678, 9876543);
foreach ($numbers as $val)
{
$r = FormatWithSlashes($val);
echo "<p>$r</p>";
}
OK, people are throwing stuff out, so I will too!
number_format would be great, because it accepts a thousands separator, but it doesn't do padding zeroes like sprintf and the like. So here's what I came up with for a one-liner:
function fmt($x) {
return substr(number_format($x+1000000000, 0, ".", "/"), 2);
}
Minor improvement to PhiLho's suggestion:
You can avoid the substr by changing the regex to:
function FormatWithSlashes($number)
{
return preg_replace('/^0*(\d{3})(\d{3})(\d{3})$/', '$1/$2/$3',
'0000' . $number);
}
I also removed the ? after each of the first two capture groups because, when given a 5, 6, or 7 digit number (as specified in the question), this will always have at least 9 digits to work with. If you want to guard against the possibility of receiving a smaller input number, run the regex against '000000000' . $number instead.
Alternately, you could use
substr('0000' . $number, -9, 9);
and then splice the slashes in at the appropriate places with substr_replace, which I suspect may be the fastest way to do this (no need to run regexes or do division), but that's really just getting into pointless optimization, as any of the solutions presented will still be much faster than establishing a network connection to the server.
This would be how I would write it if using Perl 5.10 .
use 5.010;
sub myformat(_;$){
# prepend with zeros
my $_ = 0 x ( 9-length($_[0]) ) . $_[0];
my $join = $_[1] // '/'; # using the 'defined or' operator `//`
# m// in a list context returns ($1,$2,$3,...)
join $join, m/ ^ (\d{3}) (\d{3}) (\d{3}) $ /x;
}
Tested with:
$_ = 11111;
say myformat;
say myformat(2222);
say myformat(33333,';');
say $_;
returns:
000/011/111
000/002/222
000;033;333
11111
Back-ported to Perl 5.8 :
sub myformat(;$$){
local $_ = #_ ? $_[0] : $_
# prepend with zeros
$_ = 0 x ( 9-length($_) ) . $_;
my $join = defined($_[1]) ? $_[1] :'/';
# m// in a list context returns ($1,$2,$3,...)
join $join, m/ ^ (\d{3}) (\d{3}) (\d{3}) $ /x;
}
Here's how I'd do it in python (sorry I don't know PHP as well). I'm sure you can convert it.
def convert(num): #num is an integer
a = str(num)
s = "0"*(9-len(a)) + a
return "%s/%s/%s" % (s[:3], s[3:6], s[6:9])
This just pads the number to have length 9, then splits the substrings.
That being said, it seems the modulo answer is a bit better.

Categories