-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
265 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<?php | ||
/** | ||
* Parser | ||
* | ||
* @author Pronamic <info@pronamic.eu> | ||
* @copyright 2005-2021 Pronamic | ||
* @license GPL-3.0-or-later | ||
* @package Pronamic\WordPress\Number | ||
*/ | ||
|
||
namespace Pronamic\WordPress\Number; | ||
|
||
/** | ||
* Parser | ||
* | ||
* @author Remco Tolsma | ||
* @version 2.0.0 | ||
* @since 1.1.0 | ||
*/ | ||
class Parser { | ||
/** | ||
* Parse. | ||
* | ||
* @link https://github.com/wp-pay/core/blob/2.0.2/src/Core/Util.php#L128-L176 | ||
* @param string $string String to parse as money. | ||
* @return Number | ||
* @throws \Exception Throws exception when parsing string fails. | ||
*/ | ||
public function parse( $string ) { | ||
global $wp_locale; | ||
|
||
$decimal_sep = $wp_locale->number_format['decimal_point']; | ||
|
||
// Separators. | ||
$separators = array( $decimal_sep, '.', ',' ); | ||
$separators = array_unique( array_filter( $separators ) ); | ||
|
||
// Check. | ||
foreach ( array( - 3, - 2 ) as $i ) { | ||
$test = substr( $string, $i, 1 ); | ||
|
||
if ( in_array( $test, $separators, true ) ) { | ||
$decimal_sep = $test; | ||
|
||
break; | ||
} | ||
} | ||
|
||
// Split. | ||
$position = false; | ||
|
||
if ( is_string( $decimal_sep ) ) { | ||
$position = strrpos( $string, $decimal_sep ); | ||
} | ||
|
||
// Check decimal position on -4th position at end of string of negative amount (e.g. `2.500,75-`). | ||
if ( false === $position && '-' === \substr( $string, -1, 1 ) ) { | ||
$test = substr( $string, -4, 1 ); | ||
|
||
if ( is_string( $test ) && in_array( $test, $separators, true ) ) { | ||
$position = strrpos( $string, $test ); | ||
} | ||
} | ||
|
||
if ( false !== $position ) { | ||
$full = substr( $string, 0, $position ); | ||
$half = substr( $string, $position + 1 ); | ||
|
||
/* | ||
* Consider `-` after decimal separator as alternative notation for 'no minor units' (e.g. `€ 5,-`). | ||
* | ||
* @link https://taaladvies.net/taal/advies/vraag/275/euro_komma_en_streepje_in_de_notatie_van_hele_bedragen/ | ||
*/ | ||
if ( \in_array( $half, array( '-', '–', '—' ), true ) ) { | ||
$half = ''; | ||
} | ||
|
||
$end_minus = ( '-' === \substr( $half, -1, 1 ) ); | ||
|
||
$full = filter_var( $full, FILTER_SANITIZE_NUMBER_INT ); | ||
$half = filter_var( $half, FILTER_SANITIZE_NUMBER_INT ); | ||
|
||
// Make amount negative if half string ends with minus sign. | ||
if ( $end_minus ) { | ||
// Make full negative. | ||
$full = sprintf( '-%s', $full ); | ||
|
||
// Remove minus from end of half. | ||
$half = \substr( (string) $half, 0, -1 ); | ||
} | ||
|
||
$string = $full . '.' . $half; | ||
} else { | ||
// Make amount negative if full string ends with minus sign. | ||
if ( '-' === \substr( $string, -1, 1 ) ) { | ||
$string = sprintf( '-%s', \substr( $string, 0, -1 ) ); | ||
} | ||
|
||
$string = filter_var( $string, FILTER_SANITIZE_NUMBER_INT ); | ||
} | ||
|
||
// Filter. | ||
$value = filter_var( $string, FILTER_VALIDATE_FLOAT ); | ||
|
||
if ( false === $value ) { | ||
throw new \Exception( 'Could not parse value to number object.' ); | ||
} | ||
|
||
return Number::from_mixed( $value ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
<?php | ||
/** | ||
* Parser | ||
* | ||
* @author Pronamic <info@pronamic.eu> | ||
* @copyright 2005-2021 Pronamic | ||
* @license GPL-3.0-or-later | ||
* @package Pronamic\WordPress\Number | ||
*/ | ||
|
||
namespace Pronamic\WordPress\Number; | ||
|
||
use WP_UnitTestCase; | ||
|
||
/** | ||
* Parser | ||
* | ||
* @author Remco Tolsma | ||
* @version 1.2.5 | ||
* @since 1.1.0 | ||
*/ | ||
class ParserTest extends WP_UnitTestCase { | ||
/** | ||
* Parser. | ||
* | ||
* @var Parser | ||
*/ | ||
private $parser; | ||
|
||
/** | ||
* Setup. | ||
*/ | ||
public function setUp() { | ||
parent::setUp(); | ||
|
||
$this->parser = new Parser(); | ||
} | ||
|
||
/** | ||
* Test string to amount. | ||
* | ||
* @link https://github.com/pronamic/wp-pronamic-ideal/blob/3.7.3/classes/Pronamic/WP/Pay/Settings.php#L71-L91 | ||
* @link https://github.com/WordPress/WordPress/blob/4.9.6/wp-includes/class-wp-locale.php | ||
* @link https://github.com/WordPress/WordPress/blob/4.9.6/wp-includes/functions.php#L206-L237 | ||
* | ||
* @dataProvider string_to_amount_provider | ||
* | ||
* @param string $thousands_sep Thousands seperator. | ||
* @param string $decimal_sep Decimal seperator. | ||
* @param string $string String value to convert. | ||
* @param float $expected Expected float value. | ||
*/ | ||
public function test_string_to_amount( $thousands_sep, $decimal_sep, $string, $expected ) { | ||
global $wp_locale; | ||
|
||
$wp_locale->number_format['thousands_sep'] = $thousands_sep; | ||
$wp_locale->number_format['decimal_point'] = $decimal_sep; | ||
|
||
$number = $this->parser->parse( $string ); | ||
|
||
$value = $number->get_value(); | ||
|
||
$this->assertSame( $expected, $value ); | ||
} | ||
|
||
/** | ||
* String to amount provider. | ||
* | ||
* @return array | ||
*/ | ||
public function string_to_amount_provider() { | ||
return array( | ||
// Thousands separator is '' and decimal separator is '.'. | ||
array( '', '.', '1', '1' ), | ||
array( '', '.', '2,5', '2.5' ), | ||
array( '', '.', '2,50', '2.5' ), | ||
array( '', '.', '1250,00', '1250' ), | ||
array( '', '.', '1250,75', '1250.75' ), | ||
array( '', '.', '1250.75', '1250.75' ), | ||
array( '', '.', '1.250,00', '1250' ), | ||
array( '', '.', '2.500,75', '2500.75' ), | ||
array( '', '.', '2500,75-', '-2500.75' ), | ||
array( '', '.', '-2500,75', '-2500.75' ), | ||
array( '', '.', '2500-', '-2500' ), | ||
array( '', '.', '-2500', '-2500' ), | ||
array( '', '.', '1-', '-1' ), | ||
// Thousands separator is '.' and decimal separator is ','. | ||
array( '.', ',', '1', '1' ), | ||
array( '.', ',', '2,5', '2.5' ), | ||
array( '.', ',', '2,50', '2.5' ), | ||
array( '.', ',', '1250,00', '1250' ), | ||
array( '.', ',', '2500,75', '2500.75' ), | ||
array( '.', ',', '1.250,00', '1250' ), | ||
array( '.', ',', '2.500,75', '2500.75' ), | ||
array( '.', ',', '2.500,750', '2500.75' ), | ||
array( '.', ',', '1.234.567.890', '1234567890' ), | ||
array( '.', ',', '2.500,75-', '-2500.75' ), | ||
array( '.', ',', '-2.500,75', '-2500.75' ), | ||
array( '.', ',', '2.500-', '-2500' ), | ||
array( '.', ',', '-2.500', '-2500' ), | ||
array( '.', ',', '1-', '-1' ), | ||
// Thousands separator is ',' and decimal separator is '.'. | ||
array( ',', '.', '1', '1' ), | ||
array( ',', '.', '2.5', '2.5' ), | ||
array( ',', '.', '2.50', '2.5' ), | ||
array( ',', '.', '1250.00', '1250' ), | ||
array( ',', '.', '1250.75', '1250.75' ), | ||
array( ',', '.', '1,250.00', '1250' ), | ||
array( ',', '.', '2,500.75', '2500.75' ), | ||
array( ',', '.', '2,500.', '2500' ), | ||
array( ',', '.', '2,500.75-', '-2500.75' ), | ||
array( ',', '.', '-2,500.75', '-2500.75' ), | ||
array( ',', '.', '2,500-', '-2500' ), | ||
array( ',', '.', '-2,500', '-2500' ), | ||
array( ',', '.', '1-', '-1' ), | ||
// Thousands separator is ' ' and decimal separator is '.'. | ||
array( ' ', '.', '2 500.75', '2500.75' ), | ||
// Thousands separator is 't' and decimal separator is '.'. | ||
array( 't', '.', '2t500.75', '2500.75' ), | ||
array( 't', '.', '2t500.7', '2500.7' ), | ||
// Thousands separator is 't' and decimal separator is '-'. | ||
array( 't', '-', '2t500-75', '2500.75' ), | ||
array( 't', '-', '2t500-7', '2500.7' ), | ||
// Thousands separator is 't' and decimal separator is ' '. | ||
array( 't', ' ', '2t500 75', '2500.75' ), | ||
array( 't', ' ', '2t500 7', '2500.7' ), | ||
// Thousands separator is ' ' and decimal separator is 'd'. | ||
array( ' ', 'd', '2 500d75', '2500.75' ), | ||
array( ' ', 'd', '2 500d7', '2500.7' ), | ||
array( ' ', 'd', '-2 500d75', '-2500.75' ), | ||
array( ' ', 'd', '-2 500d7', '-2500.7' ), | ||
// Other. | ||
array( '.', ',', 'EUR 1.250', '1250' ), | ||
array( '.', ',', 'EUR 1.250,75', '1250.75' ), | ||
array( '.', ',', 'EUR -1.250', '-1250' ), | ||
array( '.', ',', 'EUR -1.250,75', '-1250.75' ), | ||
array( '.', ',', '1.250,-', '1250' ), | ||
array( '.', ',', '-1.250,-', '-1250' ), | ||
array( '', '', '123456789', '123456789' ), | ||
array( false, false, '123 456 789', '123456789' ), | ||
); | ||
} | ||
} |