2

I'm trying to write a function to determine if an input is "shouting". Which hear means writing in all caps. The logic I'm using for that is

if (this.toUpperCase() === this) 

Which is working just fine, however, the problem I've having is that strictly numerical or symobolic (?, ! etc.) strings are being flagged as shouting.

I've tried something to the effect of

if (this.toUpperCase() === this && !this.match(/a-zA-Z/))

However, that doesn't seem to do the trick. Does the mistake lie in my javascript or my regex? Thanks in advance for any help!

13
  • 2
    why not !this.match(/[a-z]/) && this.match(/[A-Z]/)? Commented Mar 4, 2016 at 17:33
  • 1
    You seem to be missing the grouping, it's [a-zA-Z] Commented Mar 4, 2016 at 17:35
  • 1
    @Tomalak has a good point about i18n, but shouting is likely handled differently between cultures and that problem is too broad for this SO question. Commented Mar 4, 2016 at 17:39
  • 1
    @adeneo, I should have used this.match(/[^a-z]/) instead to make the intent clearer. Commented Mar 4, 2016 at 17:39
  • 3
    THIS EEEZN'T SHOUtIN'? Commented Mar 4, 2016 at 17:40

4 Answers 4

3

Your second condition is wrong: you're checking for a string that doesnt contain letters (upper or lowercase). And you forgot the square brackets in the regex. You should check for a string containing at least one uppercase letter:

if ((this.toUpperCase() === this) && (this.match(/[A-Z]/)))
Sign up to request clarification or add additional context in comments.

5 Comments

Uhm, wouldn't the /i make the match case-insensitive, and it would match anything
Sorry, forget about the "i" (it works in any case since first condition checks if everything is uppercase)
Please elaborate how this code answers the question.
@JAL He asked for working JS code to check if a string is uppercase, without returning true on non-letters strings. And i answered with working JS code, there's not much to explain
@JAL Btw, edited my answer to explain where the error was and how to fix it
0

You can do something like this:

var str = this;
var R = function(regex) {
    return (str.match(regex) || []).length
};
var ratio = {
    upper: R(/[A-Z]/g),
    lower: R(/[a-z]/g),
    letters: R(/[A-Z]/gi),
    spaces: R(/\s/g),
    non_letters: R(/[^A-Z]/gi)
};

and then you can use some logic like:

// if only upper case letters
if (this.length == ratio.upper + ratio.spaces)
    // do something ..

Hope it helps.

2 Comments

This is a good answer for dealing with a more realistic meaning of shouting, and using regex to do it. Obviously "shouting" is still problematic, but the ratios isn't a terrible approach
lower: R(/[A-Z]/g), should be lower: R(/[a-z]/g), methinks
0

I think Fabius' answer is what you are looking for, but I'd recommend a few changes to the logic as you may end up catching more than and not all that you want:

  • THIS IS SHOUTING!!
  • Y?
  • is the above SHOUTING?
  • Please use SSCCE.
  • wHAT ABOUT THIS? IS THIS SHOUTING?

Here's what I'd recommend:

var resultsDiv = $('#results'),
    tests = [
      { string: 'THIS IS SHOUTING!!' },
      { string: 'Y?' },
      { string: 'is the above SHOUTING?' },
      { string: 'Please use SSCCE.' },
      { string: 'wHAT ABOUT THIS? IS THIS SHOUTING?' }
    ];

$.each( tests, function(i, test){
  var string = test.string,
      isShouting;
  
  // First, strip out non-alpha characters:
  string = string.replace(/[^a-z]/ig, '');
  
  var beforeLength = string.length;
  
  // Now remove all uppercase characters:
  string = string.replace(/[^A-Z]/g, '');
  
  var afterLength = string.length;
  
  // Now, compare the length of the before and after, with a threshold for short string.
  // Basically, if the before string is at least 4 characters long and more than half of
  // the string is uppercase, then flag it as "shouting".
  isShouting =
    ( beforeLength >= 4 && ( afterLength / beforeLength >= 0.50 ) );
  
  $('<div>')
    .text(test.string)
    .css('color', 'darkblue')
    .appendTo( resultsDiv );
  
  $('<div>')
    .text(isShouting ? "SHOUTING DETECTED!" : "quiet and controlled.")
    .css('margin-bottom', '15px')
    .css('color', isShouting ? 'red' : 'black')
    .appendTo( resultsDiv );
  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="results">
</div>

You can fiddle around with the thresholds to find something that will match your expectations. 50% uppercase may be too strict. Just keep in mind that there will always be exceptions to any rule, so make sure that the consequences of "shouting" aren't too onerous.

Also note that I haven't done much to internationalize this example. I leave that as an exercise to the reader. The example above is enough to demonstrate the theory.

Comments

-2

You're asking about the regex, but your initial example doesn't use it so it sounds like you're going to regex just to cover the mistakes in the first example.

You don't need regex to do what you're looking to do.

If the string is okay to hold non-letter characters but the letters need to be all uppercase, try

if (this.toLowerCase() !== this)

to support internationalization you might want

if (this.toLocaleLowerCase() !== this)

Some languages have different casing rules, as explained in the docs toLacleLowerCase() doc

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.