{"id":24540689,"url":"https://github.com/mistralys/currency-parser","last_synced_at":"2025-10-13T04:33:34.507Z","repository":{"id":65791428,"uuid":"598539802","full_name":"Mistralys/currency-parser","owner":"Mistralys","description":"PHP library that can detect prices written in text or markup, adding non-breaking spaces, and normalising their formatting according to country-specific rules.","archived":false,"fork":false,"pushed_at":"2025-06-20T07:10:10.000Z","size":178,"stargazers_count":3,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-24T05:30:26.307Z","etag":null,"topics":["currency","filtering","normalization","parser","prices"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mistralys.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-07T10:18:47.000Z","updated_at":"2025-06-20T07:09:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"4e1b38af-1caa-428f-911b-6a81cd2fb5f1","html_url":"https://github.com/Mistralys/currency-parser","commit_stats":{"total_commits":119,"total_committers":1,"mean_commits":119.0,"dds":0.0,"last_synced_commit":"95578a35428dad390611cde9c22259b0d97b6add"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/Mistralys/currency-parser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mistralys%2Fcurrency-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mistralys%2Fcurrency-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mistralys%2Fcurrency-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mistralys%2Fcurrency-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mistralys","download_url":"https://codeload.github.com/Mistralys/currency-parser/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mistralys%2Fcurrency-parser/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279013684,"owners_count":26085390,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["currency","filtering","normalization","parser","prices"],"created_at":"2025-01-22T18:14:41.877Z","updated_at":"2025-10-13T04:33:34.491Z","avatar_url":"https://github.com/Mistralys.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Currency parser\n\nPHP library that can detect prices written in text or markup, adding \nnon-breaking spaces, and normalising their formatting according to \ncountry-specific rules.\n\n## Requirements\n\n- PHP 7.4+\n- [Composer](https://getcomposer.org)\n\n## Installation\n\nUse Composer to add the library to your project:\n\n```\ncomposer require mistralys/currency-parser\n```\n\nAlternatively, clone it locally using the GIT command line (or [GitHub Desktop](https://desktop.github.com/)),\nor manually [download a release](https://github.com/Mistralys/currency-parser/releases).\n\n## Examples of recognized formats\n\nPrimarily intended to parse prices written by humans, the parser is quite\ntolerant and will recognize any of these notations (and more) - either as\nstandalone text or scattered in a larger document.\n\n- `$1000`\n- `$1,000.00` _With thousands separators_ \n- `$ 1 , 000 . 00` _Free-spacing, including newlines_\n- `$1.000,00` _Separator style agnostic_\n- `$1.000.00` _Same separator mistake*_\n- `$1000.2` _1 to 2 decimal places_\n- `1000 EUR` _Currency symbols or names_\n- `EUR 1000` _Symbol placement agnostic_\n- `-$ 1000` _Minus before symbol_\n- `$ -1000` _Minus after symbol_\n- `50,- €` _German short style decimals_\n- `1 000,00 € TTC` _French style with VAT_\n- `.50 €` _Decimals only_\n\n\u003e * Based on the assumption that prices always have\n\u003e 1-2 decimal places, this part of the number is \n\u003e assumed to be the decimals.\n\n### _Euro_ exception\n\nThe _Euro_ is the only one of the supported currencies whose name begins\nwith the same letters as its currency name, `EUR`. The parser will \nignore prices written like this:\n\n```\n\"...and he gave him 42 Euro for his troubles.\"\n```\n\nThe reasoning being that using this name is ambiguous in a pure currency\ncontext. It is typically used when mentioning prices in body text, where\nprice formatting is not necessary or even expected. \n\n## Quick Start\n\n### Get a list of prices in a text or markup\n\n```php\nuse function Mistralys\\CurrencyParser\\findPrices;\n\n$subject = \u003c\u003c\u003cEOT\nBase price: $1,000.00\nYour price: $860.00\nEOT;\n\n$prices = findPrices($subject, 'USD');\n\nforeach($prices as $price)\n{\n    // do something with them\n}\n```\n\n### Format a single price string\n\nUsing auto-detection for all supported currencies:\n\n```php\nuse function Mistralys\\CurrencyParser\\parsePrice;\n\necho parsePrice('$1000.00')-\u003eformatText();\n```\n\nOutput:\n```\n$1,000.00\n```\n\nWith a specific currency locale for precise formatting when\nthe currency is used in several countries, like the Euro:\n\n```php\nuse function Mistralys\\CurrencyParser\\parsePrice;\n\necho parsePrice('1000.00 €', 'EUR_DE')-\u003eformatText();\n```\n\nOutput:\n```\n1.000,00 €\n```\n\n### Format all prices in a text or markup\n\nThe following will automatically format prices according to \nthe selected currencies' default locale.\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$subject = \u003c\u003c\u003c'EOT' \nStarting price: 1000.00 $\nSpecial price: € 860.00\nEOT;\n\necho PriceFilter::createForLocales('USD', 'EUR')\n    -\u003efilterString($subject);\n```\n\nOutput:\n```\nStarting price: $1,000.00\nSpecial price: 860.00 €\n```\n\nTo be more precise, the currency locale can be provided.\nFor example, Euros are formatted slightly differently in\nFrance than in the rest of Europe.\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$subject = \u003c\u003c\u003c'EOT' \nPrix de départ: EUR 1000.00\nPrix spécial: EUR 860.00\nEOT;\n\necho PriceFilter::createForLocales('EUR_FR')\n    -\u003efilterString($subject);\n```\n\nOutput:\n```\nPrix de départ: 1 000,00 EUR\nPrix spécial: 860,00 EUR\n```\n\n### Add non-breaking spaces to prices\n\nWhen formatting prices, spaces automatically get replaced by non-breaking\nspace characters for use in text documents. This can be easily switched to \nan HTML context:\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$subject = \u003c\u003c\u003c'EOT' \nStarting price: 1000.00 $\nSpecial price: 860.00 $\nEOT;\n\necho PriceFilter::createForLocales('USD')\n    -\u003esetNonBreakingSpaceHTML()\n    -\u003efilterString($subject)\n```\n\nOutput:\n```\nPrix de départ: 1 000,00 EUR\nPrix spécial: 860,00 EUR\n```\n\n### Change the currency symbol    \n\nBy default, the currency filter makes no changes to the currency symbols\nused in the document. This means that a mixed symbol usage will remain the\nsame even after formatting the numbers.\n\n#### Change to currency symbols\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$subject = \u003c\u003c\u003c'EOT'\nWith name: USD 1000\nWith symbol: $ 1000\nEOT;\n\necho PriceFilter::createForLocales('USD')\n    -\u003esetSymbolModeSymbol()\n    -\u003efilterString($subject);\n```\n\nOutput:\n```\nWith name: $1,000\nWith symbol: $1,000\n```\n\n#### Change to currency names\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$subject = \u003c\u003c\u003c'EOT'\nWith name: USD 1000\nWith symbol: $ 1000\nEOT;\n\necho PriceFilter::createForLocales('USD')\n    -\u003esetSymbolModeSymbol()\n    -\u003efilterString($subject);\n```\n\nOutput:\n```\nWith name: $1,000\nWith symbol: $1,000\n```\n\n#### Change to country preferred style\n\nFor the Euro, the preferred style is to use the currency symbol\nfor prices instead of the name. \n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$subject = \u003c\u003c\u003c'EOT'\nWith name: EUR 1000\nWith symbol: € 1000\nEOT;\n\necho PriceFilter::createForLocales('EUR_FR')\n    -\u003esetSymbolModePreferred()\n    -\u003efilterString($subject);\n```\n\nOutput:\n```\nWith name: € 1 000\nWith symbol: € 1 000\n```\n\n## Formatter usage\n\n### What is the formatter?\n\nThe formatter is used to format individual prices found in a text by the parser. \nIt knows how to format prices according to the bundled currency locales, like \nAmerican or Mexican Dollars, or French Euros. It can also be customised to format \nprices any way you like.\n\n\u003e NOTE: To format multiple prices at once, look at the Price Filter.\n\n### Locale-based formatting\n\nFire-and-forget formatting that uses the currency locale definitions.\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFormatter;\nuse function Mistralys\\CurrencyParser\\parsePrice;\n\necho PriceFormatter::createLocale('USD')\n    -\u003eformat(parsePrice('$ 1000'))\n```\n\nA locale formatter does not allow changing formatting details like the decimal\nseparator. Only the symbol mode and space character can be adjusted:\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFormatter;\nuse function Mistralys\\CurrencyParser\\parsePrice;\n\necho PriceFormatter::createLocale('USD')\n    -\u003esetNonBreakingSpaceHTML()\n    -\u003esetSymbolModeName()\n    -\u003eformat(parsePrice('$ 1000'))\n```\n\n### Custom formatting\n\nUsing a custom formatter, all formatting details can can be freely adjusted.\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFormatter;\nuse function Mistralys\\CurrencyParser\\parsePrice;\n\n$formatter = PriceFormatter::createCustom()\n    -\u003esetDecimalSeparator('[DECIMAL]')\n    -\u003esetThousandsSeparator('[THOUSAND]')\n    -\u003esetArithmeticSeparator('[ARITHMETIC]')\n    -\u003esetNonBreakingSpace('[SPACE]')\n    -\u003esetSymbolPosition(PriceFormatter::SYMBOL_POSITION_END)\n    -\u003esetSymbolSpaceAtTheEnd(PriceFormatter::SPACE_BEFORE);\n\necho $formatter-\u003eformatPrice(parsePrice('$ -1000.00'));\n```\n\nOutput:\n```\n-[ARITHMETIC]1[THOUSAND]000[DECIMAL]00[SPACE]$\n```\n\n\u003e NOTE: A formatter instance can be re-used as necessary.\n\n### Custom formatter based on a locale\n\nLet's say that we wish to use the default USD formatting, but instead of placing\nthe symbol at the beginning (default behavior), we want to display it at the end.\n\nWe have to use a custom formatter for this, but we can use an existing locale\nformatter to fill out the default settings. All that's left to do then is overwrite\nthe relevant settings.\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFormatter;\n\n$formatter = PriceFormatter::createCustom()\n    -\u003econfigureWithLocale(\\Mistralys\\CurrencyParser\\currencyLocale('USD'))\n    -\u003esetSymbolPositionAtTheEnd();\n```\n\n## Filter usage\n\n### What is the price filter?\n\nThe Filter is used to format multiple prices in text or markup documents,\nwith a minimum of code, and leaving the rest of the document intact. \n\n### Filtering a text document\n\nThe fire and forget version of filtering a document is to specify what kind\nof currencies to expect, and let the filter handle all the details based on\nhow the currency is typically formatted.\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$formatted = PriceFilter::createForLocales('USD')\n    -\u003efilterString($subject);\n```\n\n### Filtering an HTML document\n\nThis works exactly like a text document, except that the non-breaking space\ncharacter is adjusted to use the HTML style (which uses an HTML entity instead\nof the actual character).\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$formatted = PriceFilter::createForLocales('USD')\n    -\u003esetNonBreakingSpaceHTML()\n    -\u003efilterString($subject);\n```\n\n### Using custom formatters\n\nTo use a custom formatter for a currency instead of the locale-based one, the\nformatter instance must be set separately.\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\nuse Mistralys\\CurrencyParser\\PriceFormatter;\n\n// Configure a custom formatter\n$customFormatter = PriceFormatter::createCustom()\n    -\u003esetDecimalSeparator(' ')\n    -\u003esetThousandsSeparator(',')\n    -\u003esetSymbolPositionBeforeMinus()\n    -\u003esetSymbolModeName();\n\n$formatted = PriceFilter::create()\n    -\u003esetFormatter('USD', $customFormatter)\n    -\u003efilterString($subject);\n```\n\nCustom formatters and locale formatters can be freely combined. In the example\nabove, we used `PriceFilter::create()`, because all formatters were custom. \nHere, we use  a default locale formatter for french prices, and a custom one\nfor U.S. dollars:\n\n```php\nuse Mistralys\\CurrencyParser\\PriceFilter;\nuse Mistralys\\CurrencyParser\\PriceFormatter;\n\n// Configure a custom formatter\n$customFormatter = PriceFormatter::createCustom()\n    -\u003esetDecimalSeparator(' ')\n    -\u003esetThousandsSeparator(',')\n    -\u003esetSymbolPositionBeforeMinus()\n    -\u003esetSymbolModeName();\n\n$formatted = PriceFilter::createForLocales('EUR_FR')\n    -\u003esetFormatter('USD', $customFormatter)\n    -\u003efilterString($subject);\n```\n\n## Parser usage\n\n### What is the parser?\n\nThe parser is able to find prices written in arbitrary texts, including\nwithin markup (HTML or XML). It can be used as a standalone utility to access\nprice information, to do with as you please.\n\n### Detecting specific currencies\n\nTo be able to detect prices, the parser needs to know what kind of currencies\nto expect in the document. In the following example, we only use Euro prices. \n\n```php\nuse Mistralys\\CurrencyParser\\PriceParser;\n\n$subject = 'Price of a basic subscription: 50,42 €.';\n\n$prices = PriceParser::create()\n    -\u003eexpectCurrency('EUR')\n    -\u003efindPrices($subject);\n```\n\n### Detecting all currencies\n\nFor performance reasons, it is best to limit the list currencies to search for\nin a document. If this cannot be determined reliably, you may use all of them:\n\n```php\nuse Mistralys\\CurrencyParser\\PriceParser;\n\n$subject = '(document with prices here)';\n\n$prices = PriceParser::create()\n    -\u003eexpectAnyCurrency()\n    -\u003efindPrices($subject);\n```\n\n\u003e Also see the next section on how to handle currencies that share the same\n\u003e currency symbol.\n\n### Multiple possible currencies per symbol \n\nIt is possible to add multiple currencies to the parser. However, it will not \nbe able to tell them apart if they share the same symbol. Consider the following\ntext:\n\n```php\nuse Mistralys\\CurrencyParser\\PriceParser;\n\n$subject = \u003c\u003c\u003cEOT\nCanadian dollars: $1,000\nU.S. dollars: $1,000\nEOT;\n\n$prices = PriceParser::create()\n    -\u003eexpectCurrency('USD')\n    -\u003eexpectCurrency('CAD')\n    -\u003efindPrices($subject);\n    \necho $prices[0]-\u003egetCurrencyName(); // USD\necho $prices[1]-\u003egetCurrencyName(); // USD\n```\n\nThe parser will not be able to tell which of those two prices are the CAD and \nUSD ones. By default, the **parser will use `USD` in case of conflict with the\n`$` symbol**. Using currency names does not have this issue:\n\n```php\nuse Mistralys\\CurrencyParser\\PriceParser;\n\n$subject = \u003c\u003c\u003cEOT\nCanadian dollars: CAD1,000\nU.S. dollars: USD1,000\nEOT;\n\n$prices = PriceParser::create()\n    -\u003eexpectCurrency('USD')\n    -\u003eexpectCurrency('CAD')\n    -\u003efindPrices($subject);\n\necho $prices[0]-\u003egetCurrencyName(); // CAD\necho $prices[1]-\u003egetCurrencyName(); // USD\n```\n\n### Setting default currencies per symbol\n\nThe parser has built-in defaults for currency symbol conflicts, like `USD` for `$`.\nHowever, this can be adjusted if the target currency used in the document is known. \nConsider the following example:\n\n```php\nuse Mistralys\\CurrencyParser\\PriceParser;\n\n$subject = \u003c\u003c\u003cEOT\nStarting price: $35\nBlack Friday rebate: $9.99\nYour price: $25.01\nEOT;\n\n$prices = PriceParser::create()\n    -\u003eexpectCurrency('CAD')\n    -\u003esetSymbolDefault('$', 'CAD')\n    -\u003efindPrices($subject);\n\necho $prices[0]-\u003egetCurrencyName(); // CAD\necho $prices[1]-\u003egetCurrencyName(); // CAD\necho $prices[3]-\u003egetCurrencyName(); // CAD\n```\n\n\u003e If the document uses multiple currencies with the same symbol, this will not make \n\u003e it possible to distinguish between them. Only using currency names can solve such \n\u003e cases.\n\n## Mailcode compatibility\n\nThe [Mailcode](https://github.com/Mistralys/mailcode) command preprocessor uses numbers\nas placeholders for commands when safeguarding them to apply formatting filters (more\non the [reasoning behind this](https://github.com/Mistralys/mailcode#avoiding-delimiter-conflicts)). \nThis can cause placeholders of variable commands to be falsely recognized as prices.\n\nExample text with a variable command:\n\n```\nPrice from a variable: {showvar: $FOO.PRICE} EUR\n```\n\nThe `showvar` command is converted to a numeric placeholder by the safeguard feature:\n\n```\nPrice from a variable: 9990000000001999 EUR\n```\n\nTo avoid this being formatted into a price (and thus breaking the Mailcode command),\nsimply enable the Mailcode support in the currency parser via the `expectMailcode()`\nmethod:\n\n```php\nuse Mailcode\\Mailcode;\nuse Mistralys\\CurrencyParser\\PriceParser;\nuse Mistralys\\CurrencyParser\\PriceFilter;\n\n$text = 'Price from a variable: {showvar: $FOO.PRICE} EUR';\n\n// Replace Mailcode commands with placeholders\n$safeguard = Mailcode::create()-\u003ecreateSafeguard($text);\n$safeText = $safeguard-\u003emakeSafe();\n\n$currencyParser = PriceParser::create()\n    -\u003eexpectCurrency('EUR')\n    -\u003eexpectMailcode();\n\n// Format all currencies in the text\n$formattedText = PriceFilter::create($currencyParser)\n    -\u003efilterString($safeText);\n\n// Restore the Mailcode commands\n$filteredText = $safeguard-\u003emakeWhole($formattedText);\n```\n\n\u003e NOTE: This will only work with the default Mailcode placeholder delimiters. \n\u003e Using a custom delimiter is not supported.\n\n## Handling multi-currency documents\n\nIn documents with multiple currencies, if they use the same symbol (USD and CAD\nfor example), one must be set as default.\n\n\n## Philosophy\n\nThere is an excellent money library for PHP, [Money](https://github.com/moneyphp/money). \nThis library does not attempt to reproduce the same functionality - it was developed\nfor an application in particular, which requires the formatting to be fully \nwhitespace-aware. The methodology in general is focused on the filtering aspect, \nwhereas Money is a full-fledged financial calculation tool. \n\nThe two libraries can be used together: Prices have a method to get their value in\nmoney integer style.\n\n```php\n// (int)5000\n$money = \\Mistralys\\CurrencyParser\\parsePrice('$50')-\u003egetAsMoney();\n```\n\n\u003e NOTE: The built-int locale-based formatting may vary slightly from a library like \n\u003e Money. This is due to the formatting rules defined in the application for which the\n\u003e library was developed.\n\n### Contributing\n\nContributions are always welcome. The library does not currently aim to include all \nworldwide currencies, but we are open tp any you may be able to add via pull requests. \nLook in the [Currencies](https://github.com/Mistralys/currency-parser/tree/main/src/Currencies)\nfolder to get an overview of what's there.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmistralys%2Fcurrency-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmistralys%2Fcurrency-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmistralys%2Fcurrency-parser/lists"}