Hi Masood
Firstly, in response to your original question…
When working with regular expressions, you can be far more efficient with your code if you use quantifiers. For example, instead of writing (\d\d\d) you can just write \d{3}. Since you’re not sure how many digits there will be in a row, you can just search for one or more with a plus character: \d+. Each group of digits may or may not have a comma after it—in other words, the comma is optional. We can match an optional character with a question mark: \d+,?. The complete number has one or more of these groups, so our regex now looks like this: (\d+,?)+. Now you only want to match currencies (not phone numbers, years, etc), so lets’s only match strings that have one of the currency symbols before it. We can achieve this with a ‘positive lookbehind’: (?<=\$|ÂŁ|€). We’re not really interested in everything after the decimal point, so we’ll just ignore it. So… here’s our complete regex:
(?<=\$|£|€)(\d+,?)+
(For more help with regex basics, check out my article: [Getting started with regular expressions](https://inkwire.app/articles/getting-started-with-regular-expressions.html).)
So how do we combine this approach with capture groups, so you can reconstruct each number with $1, $2, etc? Unfortunately we can’t. Quantifiers don’t dynamically create groups as they go. This kind of problem isn’t one we can easily solve with regular expressions alone, so yeah… we need to write a script.
I’ve modified and simplified Ariel’s script to your purposes here. You can define a thousands separator (set to a comma by default) and whether you want to ignore 4-digit numbers (set to true by default). The script will search your selected text, or the whole story if you place your cursor anywhere in the text or select a text frame…
app.doScript (main, undefined, undefined, UndoModes.ENTIRE_SCRIPT, "Format numbers");
function main(){
// Script settings
var delimiter = ","; // Thousands separator
var ignore4 = true // Ignore 4-digit numbers?
// Get selection
var mySelection = textSelection();
if (!mySelection) {
alert("No text selected.");
return;
}
var mySourceText;
var mySelectionType = mySelection.constructor.name;
if (mySelectionType == "InsertionPoint" || mySelectionType == "TextFrame") {
// Select whole story
mySourceText = mySelection.hasOwnProperty("storyOffset") ? mySelection.storyOffset.parentStory : mySelection.insertionPoints[0].parentStory;
} else {
mySourceText = mySelection;
}
var mySearch = /(?<=\$|£|€)(\d+,?)+/;
app.findGrepPreferences = null;
app.findGrepPreferences.findWhat = mySearch.source;
var myFinds = mySourceText.findGrep();
var f, n, t;
while (f = myFinds.pop()){
n = f.contents.toString().replace(/,/g,''); // Remove existing commas from string
// Add commas to thousands
if (!ignore4 || (n && n.length > 4)){
t = n.split('').reverse().join('').match(/.{1,3}/g).join(delimiter).split('').reverse().join('');
}
t && f.contents = t;
}
function textSelection() { // Returns text-based object
if ( app.selection.length == 1 && app.selection[0].hasOwnProperty("findGrep") ) {
return (app.selection[0]);
}
// Invalid selection
return null;
}
}
Let me know if you want me to explain anything about the script. Cheers!