Back

If your email is not recognized and you believe it should be, please contact us.

  • You must be logged in to reply to this topic.Login

Comma Separator in Numbers

Return to Member Forum

  • Author
    Posts
    • #1242112
      Masood Ahmad
      Participant

      Hello Everyone,

      I hope you’re safe and keeping yourselves indoors as much as possible.

      I have a scenario where I have to change the position of the comma between the numbers. It goes like this:

      INPUT (Comma Separator as in India [2,2,3]):
      $6,737
      $6,64,559
      $6,89,566
      $26,38,400
      $8,85,67,337
      $5,17,11,889
      $20,14,52,513
      $95,35,32,752

      OUTPUT (Comma Separator as in US/UK [3,3,3]):
      $6,737
      $664,559
      $689,566
      $2,638,400
      $88,567,337
      $51,711,889
      $201,452,513
      $953,532,752

      Basic approach:
      GREP Find/Change 1:
      Find What: (\$)(\d)(\d),(\d)(\d),(\d)(\d),(\d\d\d)
      Change to: $1$2$3$4,$5$6$7,$8

      GREP Find/Change 2:
      Find What: (\$)(\d),(\d)(\d),(\d)(\d),(\d\d\d)
      Change to: $1$2$3,$4$5$6,$7

      GREP Find/Change 3:
      Find What: (\$)(\d)(\d),(\d)(\d),(\d\d\d)
      Change to: $1$2,$3$4$5,$6

      GREP Find/Change 4:
      Find What: (\$)(\d),(\d)(\d),(\d\d\d)
      Change to: $1$2$3$4,$5

      I created and merged all these four GREP queries in a single JavaScript using the ChainGREP and it worked like a charm.

      The problem with this approach is that it is limited, every time when there’s an extra digit, I have to update the code. With the above codes, I’m able to manage 9 digit numbers. I still have one more Found instance available ($9), so I can go up to ten digits, but after that, I will have to work manually.

      Is there any better way to achieve this. Any ideas will be appreciated.

      Thanks
      Masood

    • #1242134
      David Blatner
      Keymaster

      Did you see Ariel’s script? (See the comments for possible edit for Indian system)

      Script to Format Long Numbers

    • #1242274
      Masood Ahmad
      Participant

      Thanks, David, that was too quick. I already tried it, but the script won’t work if a number contain commas. So, I have to remove it first. Second, the sub-dropdown is disabled.

      However, I tried to add some code to the script to remove the existing commas:
      app.findGrepPreferences = app.changeGrepPreferences = null;
      app.findGrepPreferences.findWhat = ',';
      app.documents[0].selection[0].changeGrep();

      …and then I enabled the sub-dropdown list by commenting the line so that I can select:
      //enabled = false;

      Now I can say the script is working fine. However, I think that the dialog box should not be there and I can figure out that the actual working code lies in this area. I tried to tweak it but didn’t get any success.

      var D, E = "", G, X;
      D = decimalDropdown.selection.index ? "," : ".";
      G = delimiterDropdown.selection.index ? "\u2009" : ",";
      D == "." && E = "";
      X = "d+"+E+D+"{0,1}d+";
      app.findGrepPreferences = null;
      app.findGrepPreferences.findWhat = X;
      var myFinds = s.findGrep(), f, n, t, d;
      while (f = myFinds.pop()){
      n = f.contents.toString().split('.');
      // Add commas to thousands
      if (!ignore4.value || (n[0] && n[0].length > 4)){
      t = n[0].split('').reverse().join('').match(/.{1,3}/g).join(G).split('').reverse().join('');
      }
      // Add commas to decimals if there are any.
      if (!ignore4.value || (n[1] && n[1].length > 4)){
      n[1] && (d = n[1].match(/.{1,3}/g).join(G), t += D + d);
      }
      t && f.contents = t;
      }
      }

      Apart from this, the code also converts any numbers be it phone numbers or a year. It will be good if the script can sense numbers that starts with a Dollar($) or Pound(£) or Euro(€) symbol.

    • #1242794
      Kal Starkis
      Member

      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!

    • #1247434
      Masood Ahmad
      Participant

      Hi Kal,

      A very big thank you for writing the code for me. It really worked great. I just tweaked the ignore4 to be false as the script is just designed to look for just currencies. I really loved it.

      Secondly, I also like to thank you for briefing me about the quantifiers (). I do use them very often in my GREP codes. If I were to find numbers with comma, then your code (\d+,?)+ is the right choice. Since I need to capture the numbers, that’s why I have used \d\d\d, etc. As you said, only GREP won’t be enough, that’s why I was looking for something better. And I really got it. Thanks a lot again.

      Can you please share your email address with me at masood.designs@gmail.com

    • #1247704
      Kal Starkis
      Member

      You’re very welcome Masood! Okay, I wasn’t sure what your level of experience was with regex, but I can see why you used the approach you did. I’ll shoot you an email now.

    • #1247874
      David Test
      Member

      Bollywood crossing point with all the latest Bollywood blazing squeals of Bollywood VIPs about their lifestyle.
      bollywood gossips

Viewing 6 reply threads
  • You must be logged in to reply to this topic.
Forum Ads