DEV Community

Craig Donavin
Craig Donavin

Posted on


Building a string chopper in JS

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:

    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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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,'')
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)

  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' ]
Enter fullscreen mode Exit fullscreen mode

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?

Top comments (0)

11 Tips That Make You a Better Typescript Programmer


1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields


Read the whole post now!