g | x | w | all
Bytes Lang Time Link
076AWK250414T175804Zxrs
056Vyxal220209T222217ZSeggan
181C gcc220208T043644Zveqtrus
074Burlesque no RegEx220208T001333ZDeathInc
051Retina 0.8.2220207T161627ZNeil
064JavaScript Node.js220207T163514Znununois
171Python220207T142931ZGinger
132JavaScript Node.js220207T162847Zophact
052Charcoal220207T162807ZNeil
03605AB1E220207T152053ZKevin Cr

AWK, 76 bytes

1,$0=gsub(/(\..*){4}|[A-Z]\S*[A-Z]|[^a-zA-Z0-9\-_\.,?! ]|[!?].*[!?]|,.*,/,X)

Attempt This Online!

Similar to other regex responses, though I'm not super confident in my regex-fu.

Vyxal, 62 58 57 56 bytes

`[^\w.,?! -]`ẎL‛?!øB?ẎL1>?⌈ƛ`[A-Z]`nẎL1>;a?\.O3>?\,O1>Wa

Try it Online!

My first Vyxal answer, and I'm loving this language. So much more intuitive than Jelly. 99% sure this can be golfed more.

Explanation:

`[^\w.,?! -]`?ẎL‛?!øB?ẎL1>?⌈ƛ`[A-Z]`nẎL1>;a?\.O3>?\,O1>Wa ; Takes the word as input
`[^\w.,?! -]`ẎL                                          ; Length of any matched of illegal characters (0 if no matches)
               ‛?!                                       ; The string '?!'
                  øB                                     ; Bracketify: converts '?!' to '[?!]'
                    ?ẎL                                  ; Find all '?' and '!' and count them
                       1>                                ; More than 1?
                         ?⌈                              ; Split the input on spaces
                           ƛ            ;                ; Mapping lambda: maps all the words using the following criteria
                            `[A-Z]`nẎL                   ; How many capital letters in the word?
                                      1>                 ; More than 1?
                                         a               ; Any truthy? (i.e. any words with more than 1 capital letter?)
                                          ?\.O           ; Count full stops in string
                                              3>         ; More than 3?
                                                ?\,O     ; Count commas in string
                                                    1>   ; More than 1?
                                                      W  ; Turn the stack into a list
                                                       a ; Any truthy? (i.e. are any of the conditions true?)

Vyxal, 56 bytes

`[^\w-.,?! ]|[A-Z]\S*[A-Z]|[!?].*[!?]|,.*,|(\..*){4}`?ẎL

Try it Online!

A different version based off of the regex Node.js answer

C (gcc), 251 219 215 199 197 193 189 184 181 bytes

-32 bytes thanks to @ceilingcat

-4 bytes by subtracting 43 from c

-16 bytes by moving comparisons inside ternaries

-2 bytes by removing unneeded brackets

-4 bytes by realising that ++x>1 is equivalent to x++

-4 bytes by rearranging outer ternary and adjusting subtracted amount

-5 bytes by moving checks inside loop condition

-3 bytes by using the n array for storing the output.

#define C(l,h)c>l&c<h?n[l]++
f(char*s){int c,n[64]={1};while((c=*s++)&&!(c-=41,c+9?*n=c+8&&c-22?C(55,82)<0:C(23,50):C(6,17)<0:C(4,6)>2:C(2,4):c-4&&c-54:n[1]++:(n[23]=0)));return*n;}

Try it online!

The C macro increments a counter for a character class. I used decimal literals instead of char literals. When a space is encountered the uppercase counter is reset.

Burlesque (no RegEx), 103 88 81 76 74 bytes

Jwd{qsnfl2.<}aljJbc".,?!"qCNZ]^p.+1<=j1<=&&j3<=&&jNBqrifn" -_.,?!"\\z?&&&&

Try it online!

Almost certainly a shorter answer possible. This is pretty brute force.

Jwd{qsnfl2.<}alj  # Check double caps

J       # Duplicate input
wd      # Split into words
{      
 qsn    # isUpper
 fl     # filter length
 2.<    # <2
}       #
al      # All
j       # Swap input to top of stack

Jbc".,?!"qCNZ]^p.+1<=j1<=&&j3<=&&j  # Check char counts

J       # Duplicate input
bc      # Box and repeat infinitely
".,?!"  # String
qCN     # Count occurences
Z]      # Zip with count (return list of counts for each)
^p      # Push list to stack
.+      # Add ?s and !s
1<=j    # ?+! <= 1
1<=&&j  # , <= 1
3<=&&   # . <= 3

NBqrifn" -_.,?!"\\z?  # Check valid chars

NB          # Remove duplicates
qri         # Quoted is alphanum
fn          # Filter not
" -_.,?!"   # Valid non-letter
\\          # List diff
z?          # Empty

&&&&        # Reduce all 3 by ands

Retina 0.8.2, 55 53 51 bytes

[^-.,?!\w ]|[?!].*[?!]|,.*,|(\..*){4}|[A-Z]\S*[A-Z]

Try it online! Link includes test cases. Edit: Saved 2 bytes thanks to @Ausername and another 2 bytes thanks to @nununoisy. Simply reports on the number of banned patterns it finds, so for some spam the truthy value might be greater than 1; if this is undesirable, 1` can be prefixed to the program which limits the count to 1. Explanation:

[^-.,?!\w ]     Check for illegal characters.
[?!].*[?!]      Check for two question or exclamation marks.
,.*,            Check for two commas.
(\..*){4}       Check for four or more full stops.
[A-Z]\S*[A-Z]   Check for two uppercase letters in the same word.

JavaScript (Node.js), 72 71 68 64 bytes

-1 byte thanks to @ThisFieldIsRequired

-3 bytes inspired by @Neil's Retina answer

-2 bytes thanks to @emanresuA (see @Neil's answer)

-2 bytes by modifying final test slightly

m=>/[^\w-.,?! ]|[A-Z]\S*[A-Z]|[!?].*[!?]|,.*,|(\..*){4}/.test(m)

Try it online!

Regex abuse FTW.

Here's how it works:

If you put these together in a single regex as alternates, you get a spam filter that matches all criteria.

Python, 177 171 bytes

This requires the re module, so that adds an additional 9 bytes.

lambda i:any([re.search('[^a-zA-Z0-9\-.\,\?\! ]',i),*[len(re.findall("[A-Z]",w))>1for w in i.split(" ")],len(re.findall('[?!]'))>1,i.count(".")>3,i.count(",")>1])

Attempt This Online!

JavaScript (Node.js), 132 bytes

n=>n.split` `.some(w=>/[^\w-.,?!]/.test(w)+(F=C=>w.split(C).length-1,c+=F`.`,d+=F(/[?!]/),e+=F`,`,F(/[A-Z]/)>1),c=d=e=0)|c>3|d>1|e>1

Try it online!

If you want to be completely sure that the answer works, add a backslash before the dash in the first regular expression. The code above passes all test cases, but a comment on the python answer seems to indicate that there should be a backslash or space before the dash. If anyone could confirm or disprove the statement above, it would be very helpful.

Charcoal, 52 bytes

⌈⟦⊙θ¬№⁺ !,-.?_⭆⁶²⍘λφι‹¹⁺№θ!№θ?‹¹№θ,‹³№θ.⊙⪪θ ‹¹LΦι№αλ

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for spam, nothing if not. Explanation:

⌈⟦

Output if any of the following is true.

⊙θ¬№⁺ !,-.?_⭆⁶²⍘λφι

Check whether any characters aren't contained in the permitted list including the 62 alphanumeric characters used by default for base conversion.

‹¹⁺№θ!№θ?

Check whether there is more than one exclamation or question mark.

‹¹№θ,

Check whether there is more than one comma.

‹³№θ.

Check whether there are more than three full stops.

⊙⪪θ ‹¹LΦι№αλ

Check whether any word has more than one upper case letter.

05AB1E, 38 37 36 bytes

žj…,!?©… -.JÃÊ·IS#.uOI®S¢ā£OI'.¢;M2@

Try it online or verify all test cases.

Explanation:

žj              # "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
  …,!?          # Push string ",!?"
      ©         # Store it in variable `®` (without popping)
       … -.     # Push string " -."
           J    # Join all three strings on the stack together
            Ã   # Only keep those characters from the (implicit) input
             Ê  # Check if it's now NOT equal to the (implicit) input
              · # Double it (2 if truthy; 0 if falsey)
I               # Push the input
 S              # Convert it to a list of characters
  #             # Split it on spaces
   .u           # Check for each character if it's an uppercased letter
     O          # Sum those checks for each word
 ®S             # Push [",","!","?"] (variable `®` as list of characters)
I  ¢            # Count these characters in the input
    ā           # Push a list in the range [1,length] (without popping): [1,2,3]
     £          # Split the counts into those parts: [[a],[b,c],[]]
                # (a=count of ","; b=count of "!"; c=count of "?")     
      O         # Sum each inner list: [a,b+c,0]
I               # Push the input yet again
 '.¢           '# Count the amount of "." in the input
    ;           # Halve it
M               # Push the largest number of the stack (including within lists)
 2@             # Check if this max is ≥2
                # (after which it is output implicitly as result)