Question: I'm a fiction writer and I used to do my writing in MS Word. I've written some macros to help me edit the fiction text and one of them check the paragraph and marks (red) the duplicate (or triplicate words, etc). Example:

```
"I came **home**. And while at **home** I did this and that."

```

Word "home" is used twice and worth checking if I really can't change the sentence.

Now I mostly use google documents for writing, but I still have to do my editing in MS Word, mostly just because of this macro - I am not able to program it in the google script.

```html
function PobarvajBesede() {
    var doc = DocumentApp.getActiveDocument();
    var cursor = DocumentApp.getActiveDocument().getCursor();
    var surroundingText = cursor.getSurroundingText().getText();
    var WordsString = WORDS(surroundingText);
    Logger.log(WordsString);
//so far, so good. But this doesn't work:
    var SortedWordsString =  SORT(WordsString[1],1,False);
// and I'm lost.
}

function WORDS(input) {
  var input = input.toString();
  var inputSplit = input.split(" ");
//  Logger.log(inputSplit);
  inputSplit = inputSplit.toString();

  var punctuationless = inputSplit.replace(/[.,\/#!$%\?^&\*;:{}=\-_`~()]/g," ");
  var finalString = punctuationless.replace(/\s{2,}/g," ");
  finalString = finalString.toLowerCase();
  return finalString.split(" ") ;
}
```

If I could only get a list of words (in uppercase, longer than 3 characters), sorted by the number of their appearances in the logger, it would help me a lot:

```
HOME (2)
AND (1)
...

```

Thank you.

Answer: 
### Flow:

* Transform the string to upper case and sanitize the string of all non ascii characters
* After splitting the string to word array, reduce the array to a object of word:count
* Map the reduced object to a 2D array `[[word,count of this word],[..],...]` and sort the array by the inner array's count.

### Snippet:

```js
function wordCount(str) {
  str = str || 'I came **home**. And while at **home** I did this and that.';
  var countObj = str
.toUpperCase() //'I CAME **HOME**...'
.replace(/[^A-Z ]/g, '') //'I CAME HOME...'
.split(' ') //['I', 'CAME',..]
.reduce(function(obj, word) {
  if (word.length >= 3) {
    obj[word] = obj[word] ? ++obj[word] : 1;
  }
  return obj;
}, {}); //{HOME:2,DID:1}

  return Object.keys(countObj)
.map(function(word) {
  return [word, countObj[word]];
}) //[['HOME',2],['CAME',1],...]
.sort(function(a, b) {
  return b[1] - a[1];
});
}
console.info(wordCount());
```

To read and practice:
---------------------

* [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
* [Array methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Methods_2)
This is a combination of TheMaster answer and some of my work. I need to learn more about the way he did it so I spent some learning time today. This function eliminates some problems I was having the carriage returns and it also removes items that only appear once. You should probably pick TheMasters solution as I couldn't have done it without his work.

```
function getDuplicateWords() {
  var str=DocumentApp.getActiveDocument().getBody().getText(); 
  var countObj = str
  .toUpperCase()
  .replace(/\n/g,' ')
  .replace(/[^A-Z ]/g, '')
  .split(' ')
  .reduce(function(obj, word) {
    if (word.length >= 2) {
      obj[word] = obj[word] ? ++obj[word] : 1;
    }
    return obj;
  }, {}); 
  var oA=Object.keys(countObj).map(function(word){return [word, countObj[word]];}).filter(function(elem){return elem[1]>1;}).sort(function(a,b){return b[1]-a[1]});
  var userInterface=HtmlService.createHtmlOutput(oA.join("<br />"));
  DocumentApp.getUi().showSidebar(userInterface);
}

function onOpen() {
  DocumentApp.getUi().createMenu('MyMenu')
  .addItem('Get Duplicates','getDuplicateWords' )
  .addToUi();
}

```

And yes I was having problems with get the results to change in my last solution.