Building a string chopper in JS
Tags: javascript
Published: 2020-12-01 17:50:44

For today’s post, I will attempt to create a string chopper. The string chopper will take a given string, and performs a number of compressions and divisions to it. For what purpose would I need such a thing? Well, at my job, people are required to perform searches for database entries that contain a version of a brand or product name, such as “HRSHY” or “HERSH” for Hershey’s or “CHCL” or “CHOC” for chocolate. A typical step in the beginning of a ticket for us is taking the brand and product names and parsing them out into searchable query terms. 

The API we use for finding and attributing these entries gives us a lot of search options, like “starts with”, “!=”, and other operations. It’s also got some front-end protection, so that an improperly entered query simply won’t run, and something that gives too big a return (350k+ rows) only returns partial data. This is all to say that there’s a bit of lenience in what search terms I can use. `entries containing con`, where `con` is the search term might be a little broad, but `entries containing coin` should be fine. 

The best practices are: 
Query terms should be 3-5 letters.
Simpler the better, but watch for “common” terms, such as prefixes and suffixes
whitespace/whitespace characters can be used but must be wrapped in quotes
Probably ten or eleven things that are hugely important, but also not really relevant to a blog post. 

Essentially, this abstracts a process of querying our DB, so that instead of going 

`SELECT * FROM receipt_db WHERE name INCLUDES [query term]`

we can just type ‘entries containing [query term]’ into a search bar and away we go.

So how do we start this? My first attempt will be in JavaScript, and if I’m successful, I’ll try to rewrite it in Ruby.

My usual method of writing something like this would go:

```
function(string){
	assign return container
	build an iterator that chops the string into substrings of the desired length
		push the substrings into a container
	return the container
}
```

Here’s a go at it:

```
function chopper3(str) {
  let retArr = [] // make a container to put the results into
  for (let i=0; i<str.length; i++) {
    let slice = str.slice(i, i+3)
    str.slice(i, i+3).length === 3 ? retArr.push(slice) : i++
  } // create an interator, make slices three characters long, push them into array
  return retArr
}
```

Alright, now what can we do better? For one, our function needs to produce substrings of 3, 4, and 5 characters long. So, I could either write the function three times with updated numbers. Or! That sounds like an argument should be thrown in. Let’s give this a try:

```
function chopper(str, charLgnth){
  let retArr = []
  for (let i=0; i<str.length; i ++) {
    let subStr = str.slice(i, i + charLgnth)
    subStr.length === charLgnth ? retArr.push(subStr) : i++
  }
  return retArr
}
```

Now, how about if I want to produce a version without vowels, so I could be given query terms for “HRSH” or “CHCL”? Removing the vowels from a string is a pretty classic JS exercise, and there’s a few ways to do it. The lucky part is that memory/resource usage isn’t really a concern, so I could do it in pretty much any way I want to.

One way would be to split and then if the element was a vowel we would skip it (if iterating) or remove it (if filtering) and then join it again. Or we could just use regex:

```
function removeVowels(str) {
  return str.replace(/[aeiou]/ig,'')
}
```

So we’re replacing any match to any of these characters with nothing, case insensitive and global options added.
If you want to do it the long way (which might be an interview question, or at least a component of one), please toss your go at it in the comments.

Now let’s refactor our chopper to include the remove vowels option. We’ll use a boolean argument, since we just need to know whether to run it or not.

```
function chopper(str, charLgnth, vowel){
  if (vowel) {
    str = removeVowels(str)
  }
  let retArr = []
  for (let i=0; i<str.length; i ++) {
    let subStr = str.slice(i, i + charLgnth)
    subStr.length === charLgnth ? retArr.push(subStr) : i++
  }
  return retArr
}
```

Currently, the output is an object with a bunch of arrays in it. 
```
let input = "hersheys" //<-- Enter the word you want to chop here 
let queryObj = {
  threeLetter: chopper(input, 3),
  fourLetter: chopper(input, 4),
  fiveLetter: chopper(input, 5),
  noVowelsThree: chopper(input, 3, true),
  noVowelsFour: chopper(input, 4, true),
  noVowelsFive: chopper(input, 5, true)
}
console.log(input)
console.log(removeVowels(input))
console.log(queryObj)

hersheys
hrshys
{
  threeLetter: [ 'her', 'ers', 'rsh', 'she', 'hey', 'eys' ],
  fourLetter: [ 'hers', 'ersh', 'rshe', 'shey', 'heys' ],
  fiveLetter: [ 'hersh', 'ershe', 'rshey', 'sheys' ],
  noVowelsThree: [ 'hrs', 'rsh', 'shy', 'hys' ],
  noVowelsFour: [ 'hrsh', 'rshy', 'shys' ],
  noVowelsFive: [ 'hrshy', 'rshys' ]
}
```
There are also some “bad” queries in here, too, meaning some query terms that wouldn’t be particularly useful, such as “her”, “hers”, “she”, etc. Also, sometimes, you want to include maybe one vowel. So let’s make those our next couple projects with this:
*Inserting a vowel at a time
*Getting rid of “bad” queries

What else should we consider with this bunch of code? And how should I make it useable at work?