Determine sentence type

From Rosetta Code
(Redirected from Determine Sentence Type)
Task
Determine sentence type
You are encouraged to solve this task according to the task description, using any language you may know.

Use these sentences: "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it”

Task
Search for the last used punctuation in a sentence, and determine its type according to its punctuation.
Output one of these letters
"E" (Exclamation!), "Q" (Question?), "S" (Serious.), "N" (Neutral).
Extra
Make your code able to determine multiple sentences.


Don't leave any errors!


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



11l

Translation of: Go
F sentenceType(s)
   I s.empty
      R ‘’

   [Char] types
   L(c) s
      I c == ‘?’
         types.append(Char(‘Q’))
      E I c == ‘!’
         types.append(Char(‘E’))
      E I c == ‘.’
         types.append(Char(‘S’))

   I s.last !C ‘?!.’
      types.append(Char(‘N’))

   R types.join(‘|’)

V s = ‘hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it’
print(sentenceType(s))
Output:
Q|S|E|N

AArch64 Assembly

Works with: as version Raspberry Pi 3B version Buster 64 bits
or android 64 bits with application Termux
/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program detertype64.s   */
   

/*******************************************/
/* Constantes                              */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc" 

.equ BUFFERSIZE,    160
.equ SENTENCESTART,  3
/*******************************************/
/*   Macros                              */
/*******************************************/
//.include "../../ficmacros64.inc"            // for developer debugging

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessDebutPgm:   .asciz "Program 64 bits start. \n"
szCarriageReturn: .asciz "\n"
szMessFinOK:      .asciz "Program normal end. \n"
szMessErreur:     .asciz "Error  !!!\n"
szSpace1:         .asciz " "

szPhrase1:          .ascii "hi there, how are you today?"
                    .ascii "I'd like to present to you the washing machine 9001."
                    .ascii " You have been nominated to win one of these!"
                    .asciz " Just make sure you don't break it"
.equ LGPHRASE1,  . -  szPhrase1 - 1

         
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4

/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:
    ldr x0,qAdrszMessDebutPgm
    bl affichageMess               // start message 
    sub sp,sp,#BUFFERSIZE
    mov x7,sp
    ldr x4,qAdrszPhrase1            // load phrase adress 
    mov x5,#0
    mov x6,#SENTENCESTART
1:
    ldrb w1,[x4,x5]
    strb w1,[x7,x6]
    add x6,x6,#1
    cmp x1,#0
    beq 10f
    cmp x1,#'.'
    mov x2,#'S'
    beq 2f
    cmp x1,#'?'
    mov x2,#'Q'
    beq 2f
    cmp x1,#'!'
    mov x2,#'E'
    beq 2f
    
    add x5,x5,#1
    b 1b
 2:
    mov x0,x7
    mov x1,x6
    bl traitResult
    mov x6,#SENTENCESTART
    add x5,x5,#1
    b 1b 
 
10:
    cmp x6,#SENTENCESTART
    beq 11f
    mov x0,x7
    mov x2,#'N'
    sub x1,x6,#1
    bl traitResult
11:   
    ldr x0,qAdrszMessFinOK
    bl affichageMess       
    b 100f
99:
    ldr x0,qAdrszMessErreur        // error
    bl affichageMess
    mov x0, #1                     // return code error
    b 100f
100: 
    add sp,sp,#BUFFERSIZE
    mov x8,EXIT 
    svc #0                         // system call
qAdrszMessDebutPgm:          .quad szMessDebutPgm
qAdrszMessFinOK:             .quad szMessFinOK
qAdrszMessErreur:            .quad szMessErreur 
qAdrszPhrase1:               .quad szPhrase1
/***************************************************/
/*   display result                  */
/***************************************************/
/* x0 contains buffer address  */
/* x1 contains buffer length */
/* x2 contains characters type */
traitResult:
    stp x3,lr,[sp,-16]!         // save  registers 
    mov x3,#0x0A        // return line
    strb w3,[x0,x1]  
    add x1,x1,#1    
    mov x3,#0
    strb w3,[x0,x1]     // final zero
    strb w2,[x0]        // store character type
    mov x3,#':'
    strb w3,[x0,#1]
    mov x3,#' '
    strb w3,[x0,#2]
    bl affichageMess
 
 100:                   // end function
    ldp x3,lr,[sp],16         // restaur  registers 
    ret

/***************************************************/
/*      ROUTINES INCLUDE                 */
/***************************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeARM64.inc"
Output:
Program 64 bits start.
Q: hi there, how are you today?
S: I'd like to present to you the washing machine 9001.
E:  You have been nominated to win one of these!
N:  Just make sure you don't break it
Program normal end.

Ada

-- Rosetta Code Task written in Ada
-- Determine sentence type
-- https://rosettacode.org/wiki/Determine_sentence_type
-- July 2024, R. B. E.

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;

procedure Determine_Sentence_Type is
  S1 : String := "hi there, how are you today?";
  S2 : String := "I'd like to present to you the washing machine 9001.";
  S3 : String := "You have been nominated to win one of these!";
  S4 : String := "Just make sure you don't break it";

  procedure Just_Do_It (S: String) is
  begin
    if (S'Last = 0) then  
      Put_Line ("Error: The provided sentence was empty.");
    else
      case S (S'Last) is
        when '?' => Put ("Q: ");
        when '.' => Put ("S: ");
        when '!' => Put ("E: ");
        when others => Put ("N: ");
      end case;
      Put_Line (S);
    end if;
  end Just_Do_It;

begin
  Just_Do_It (S1);
  Just_Do_It (S2);
  Just_Do_It (S3);
  Just_Do_It (S4);
end Determine_Sentence_Type;
Output:
Q: hi there, how are you today?
S: I'd like to present to you the washing machine 9001.
E: You have been nominated to win one of these!
N: Just make sure you don't break it

ALGOL 68

Classifies an empty string as "".

BEGIN # determuine the type of a sentence by looking at the final punctuation  #
    CHAR exclamation = "E"; # classification codes... #
    CHAR question    = "Q";
    CHAR serious     = "S";
    CHAR neutral     = "N";
    # returns the type(s) of the sentence(s) in s - exclamation, question,     #
    #                     serious or neutral; if there are multiple sentences  #
    #                     the types are separated by |                         #
    PROC classify = ( STRING s )STRING:
         BEGIN
            STRING result := "";
            BOOL pending neutral := FALSE; 
            FOR s pos FROM LWB s TO UPB s DO
                IF   pending neutral := FALSE;
                     CHAR c = s[ s pos ];
                     c = "?"
                THEN result +:= question    + "|"
                ELIF c = "!"
                THEN result +:= exclamation + "|"
                ELIF c = "."
                THEN result +:= serious     + "|"
                ELSE pending neutral := TRUE
                FI
            OD;
            IF   pending neutral
            THEN result +:= neutral + "|"
            FI;
            # if s was empty, then return an empty string, otherwise remove the final separator #
            IF result = "" THEN "" ELSE result[ LWB result : UPB result - 1 ] FI
         END # classify # ;
    # task test case #
    print( ( classify( "hi there, how are you today? I'd like to present to you the washing machine 9001. "
                     + "You have been nominated to win one of these! Just make sure you don't break it"
                     )
           , newline
           )
         )
END
Output:
Q|S|E|N

ARM Assembly

Works with: as version Raspberry Pi
or android 32 bits with application Termux
/* ARM assembly Raspberry PI  */
/*  program detertype.s   */
   
/* REMARK 1 : this program use routines in a include file 
   see task Include a file language arm assembly 
   for the routine affichageMess conversion10 
   see at end of this program the instruction include */

/*******************************************/
/* Constantes                              */
/*******************************************/
.include "../constantes.inc"

.equ BUFFERSIZE,    200
.equ SENTENCESTART,  3
/*******************************************/
/*   Macros                              */
/*******************************************/
//.include "../../ficmacros32.inc"            @ for developer debugging

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessDebutPgm:   .asciz "Program 32 bits start. \n"
szCarriageReturn: .asciz "\n"
szMessFinOK:      .asciz "Program normal end. \n"
szMessErreur:     .asciz "Error  !!!\n"
szSpace1:         .asciz " "

szPhrase1:          .ascii "hi there, how are you today?"
                    .ascii "I'd like to present to you the washing machine 9001."
                    .ascii " You have been nominated to win one of these!"
                    .asciz " Just make sure you don't break it"
.equ LGPHRASE1,  . -  szPhrase1 - 1

         
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4

/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:
    ldr r0,iAdrszMessDebutPgm
    bl affichageMess               @ start message 
    sub sp,sp,#BUFFERSIZE
    mov r7,sp
    ldr r4,iAdrszPhrase1            @ load phrase adress 
    mov r5,#0
    mov r6,#SENTENCESTART
1:
    ldrb r1,[r4,r5]
    strb r1,[r7,r6]
    add r6,r6,#1
    cmp r1,#0
    beq 10f
    cmp r1,#'.'
    moveq r2,#'S'
    beq 2f
    cmp r1,#'?'
    moveq r2,#'Q'
    beq 2f
    cmp r1,#'!'
    moveq r2,#'E'
    beq 2f
    
    add r5,r5,#1
    b 1b
 2:
    mov r0,r7
    mov r1,r6
    bl traitResult
    mov r6,#SENTENCESTART
    add r5,r5,#1
    b 1b 
 
10:
    cmp r6,#SENTENCESTART
    beq 11f
    mov r0,r7
    mov r2,#'N'
    sub r1,r6,#1
    bl traitResult
11:   
    ldr r0,iAdrszMessFinOK
    bl affichageMess       
    b 100f
99:
    ldr r0,iAdrszMessErreur        @ error
    bl affichageMess
    mov r0, #1                     @ return code error
    b 100f
100: 
    add sp,sp,#BUFFERSIZE
    mov r7,#EXIT                   @ program end
    svc #0                         @ system call
iAdrszMessDebutPgm:          .int szMessDebutPgm
iAdrszMessFinOK:             .int szMessFinOK
iAdrszMessErreur:            .int szMessErreur 
iAdrszPhrase1:               .int szPhrase1
/***************************************************/
/*   display result                  */
/***************************************************/
/* r0 contains buffer address  */
/* r1 contains buffer length */
/* r2 contains characters type */
traitResult:
    push {r3,lr}        @ save registers 
    mov r3,#0x0A        @ return line
    strb r3,[r0,r1]  
    add r1,r1,#1    
    mov r3,#0
    strb r3,[r0,r1]     @ final zero
    strb r2,[r0]        @ store character type
    mov r3,#':'
    strb r3,[r0,#1]
    mov r3,#' '
    strb r3,[r0,#2]
    bl affichageMess
 
 100:                   @ end function
    pop {r3,pc}         @ restaur registers 

/***************************************************/
/*      ROUTINES INCLUDE                 */
/***************************************************/
.include "../affichage.inc"
Output:
Program 32 bits start.
Q: hi there, how are you today?
S: I'd like to present to you the washing machine 9001.
E:  You have been nominated to win one of these!
N:  Just make sure you don't break it
Program normal end.

Asymptote

Translation of: GW-BASIC
string[] spam = {
    "hi there, how are you today?",
    "I'd like to present to you the washing machine 9001.",
    "You have been nominated to win one of these!",
    "Just make sure you don't break it"
};

string SentenceType(string s) {
    int len = length(s);
    string lastChar = substr(s, len-1, len);
    if (lastChar == "?") return "Q";
    if (lastChar == "!") return "E";
    if (lastChar == ".") return "S";
    return "N";
}

for (int i = 0; i < spam.length; ++i) {
    write(spam[i] + " -> " + SentenceType(spam[i]));
}

AutoHotkey

Sentence := "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it"
Msgbox, % SentenceType(Sentence)

SentenceType(Sentence) {
	Sentence := Trim(Sentence)
	Loop, Parse, Sentence, .?!
	{
		N := (!E && !Q && !S)
		, S := (InStr(SubStr(Sentence, InStr(Sentence, A_LoopField)+StrLen(A_LoopField), 3), "."))
		, Q := (InStr(SubStr(Sentence, InStr(Sentence, A_LoopField)+StrLen(A_LoopField), 3), "?"))
		, E := (InStr(SubStr(Sentence, InStr(Sentence, A_LoopField)+StrLen(A_LoopField), 3), "!"))
		, type .= (E) ? ("E|") : ((Q) ? ("Q|") : ((S) ? ("S|") : "N|"))
		, D := SubStr(Sentence, InStr(Sentence, A_LoopField)+StrLen(A_LoopField), 3)
	}
	return (D = SubStr(Sentence, 1, 3)) ? RTrim(RTrim(type, "|"), "N|") : RTrim(type, "|")
}
Output:
Q|S|E|N

AWK

# syntax: GAWK -f DETERMINE_SENTENCE_TYPE.AWK
BEGIN {
    str = "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it"
    main(str)
    main("Exclamation! Question? Serious. Neutral")
    exit(0)
}
function main(str,  c) {
    while (length(str) > 0) {
      c = substr(str,1,1)
      sentence = sentence c
      if (c == "!") {
        prn("E")
      }
      else if (c == ".") {
        prn("S")
      }
      else if (c == "?") {
        prn("Q")
      }
      str = substr(str,2)
    }
    prn("N")
    print("")
}
function prn(type) {
    gsub(/^ +/,"",sentence)
    printf("%s %s\n",type,sentence)
    sentence = ""
}
Output:
Q hi there, how are you today?
S I'd like to present to you the washing machine 9001.
E You have been nominated to win one of these!
N Just make sure you don't break it

E Exclamation!
Q Question?
S Serious.
N Neutral

BASIC

Applesoft BASIC

The GW-BASIC solution works without any changes.

BASIC256

arraybase 1
dim spam$(4)
spam$[1] = "hi there, how are you today?"
spam$[2] = "I'd like to present to you the washing machine 9001."
spam$[3] = "You have been nominated to win one of these!"
spam$[4] = "Just make sure you don't break it"

for i = 1 to 4
    print spam$[i]; " -> "; SentenceType$(spam$[i])
next i
end

function SentenceType$ (s$)
    l$ = right(s$, 1)
    begin case
        case l$ = "?"
            SentenceType$ = "Q"
        case l$ = "!"
            SentenceType$ = "E"
        case l$ = "."
            SentenceType$ = "S"
        else
            SentenceType$ = "N"
    end case
end function

Chipmunk Basic

Works with: Chipmunk Basic version 3.6.4
100 sub sentencetype$(s$)
110   select case right$(s$,1)
120     case "?"
130       sentencetype$ = "Q"
140     case "!"
150       sentencetype$ = "E"
160     case "."
170       sentencetype$ = "S"
180     case else
190       sentencetype$ = "N"
200   end select
210 end sub
220 dim spam$(3)
230 spam$(0) = "hi there, how are you today?"
240 spam$(1) = "I'd like to present to you the washing machine 9001."
250 spam$(2) = "You have been nominated to win one of these!"
260 spam$(3) = "Just make sure you don't break it"
270 for i = 0 to ubound(spam$)
280   print spam$(i);" -> ";sentencetype$(spam$(i))
290 next i

FreeBASIC

function sentype( byref s as string ) as string
    'determines the sentence type of the first sentence in the string
    'returns "E" for an exclamation, "Q" for a question, "S" for serious
    'and "N" for neutral.
    'modifies the string to remove the first sentence
    for i as uinteger = 1 to len(s)
        if mid(s, i, 1) = "!" then
            s=right(s,len(s)-i)
            return "E"
        end if
        if mid(s, i, 1) = "." then
            s=right(s,len(s)-i)
            return "S"
        end if 
        if mid(s, i, 1) = "?" then
            s=right(s,len(s)-i)
            return "Q"
        end if 
    next i
    'if we get to the end without encountering punctuation, this
    'must be a neutral sentence, which can only happen as the last one
    s=""
    return "N"
end function

dim as string spam = "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it"

while len(spam)>0
    print sentype(spam)
wend
Output:
Q

S E N

FutureBasic

local fn SentenceType( sentence as CFStringRef ) as CFStringRef
  CFStringRef type
  select ( fn StringCharacterAtIndex( sentence, len(sentence)-1 ) )
    case _"?" : type = @"Q"
    case _"." : type = @"S"
    case _"!" : type = @"E"
    case else : type = @"N"
  end select
end fn = type

print fn SentenceType( @"hi there, how are you today?" )
print fn SentenceType( @"I'd like to present to you the washing machine 9001." )
print fn SentenceType( @"You have been nominated to win one of these!" )
print fn SentenceType( @"Just make sure you don't break it" )

HandleEvents
Output:
Q
S
E
N

Gambas

Public spam As String[] = ["hi there, how are you today?", "I'd like to present to you the washing machine 9001.", "You have been nominated to win one of these!", "Just make sure you don't break it"]

Public Sub Main() 

  For i As Integer = 0 To spam.Count - 1
    Print spam[i]; " -> "; SentenceType(spam[i]) 
  Next

End 

Function SentenceType(ByRef s As String) As String 

  Select Case Right(s, 1) 
    Case "?" 
      Return "Q" 
    Case "!" 
      Return "E" 
    Case "." 
      Return "S" 
    Case Else 
      Return "N" 
  End Select 

End Function

GW-BASIC

Translation of: Chipmunk Basic
Works with: PC-BASIC version any
Works with: BASICA
Works with: Applesoft BASIC
Works with: Chipmunk Basic
Works with: QBasic
Works with: MSX BASIC
100 CLS : rem  100 HOME for Applesoft BASIC
110 DIM SPAM$(3)
120 SPAM$(0) = "hi there, how are you today?"
130 SPAM$(1) = "I'd like to present to you the washing machine 9001."
140 SPAM$(2) = "You have been nominated to win one of these!"
150 SPAM$(3) = "Just make sure you don't break it"
160 FOR I = 0 TO 3
170   LASTCHAR$ = RIGHT$(SPAM$(I), 1)
180   IF LASTCHAR$ = "?" THEN TYPE$ = "Q"
190   IF LASTCHAR$ = "!" THEN TYPE$ = "E"
200   IF LASTCHAR$ = "." THEN TYPE$ = "S"
210   IF LASTCHAR$ <> "?" AND LASTCHAR$ <> "!" AND LASTCHAR$ <> "." THEN TYPE$ = "N"
220   PRINT SPAM$(I) + " -> " + TYPE$
230 NEXT I
240 END
Output:
hi there, how are you today? -> Q
I'd like to present to you the washing machine 9001. -> S
You have been nominated to win one of these! -> E
Just make sure you don't break it -> N

MSX Basic

Works with: MSX BASIC version any

The GW-BASIC solution works without any changes.

PureBasic

Procedure.s SentenceType(s.s)
  Select Right(s, 1)
    Case "?"
      ProcedureReturn "Q"
    Case "!"
      ProcedureReturn "E"
    Case "."
      ProcedureReturn "S"
    Default
      ProcedureReturn "N"
  EndSelect
EndProcedure

Dim spam.s(3)
spam(0) = "hi there, how are you today?"
spam(1) = "I'd like to present to you the washing machine 9001."
spam(2) = "You have been nominated to win one of these!"
spam(3) = "Just make sure you don't break it"

OpenConsole()
For i = 0 To 3
  PrintN(spam(i) + " -> " + SentenceType(spam(i)))
Next i

PrintN(#CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()

QBasic

Works with: QBasic version 1.1
Works with: QuickBasic version 4.5
Works with: QB64
DECLARE FUNCTION SentenceType$ (s AS STRING)

Dim spam(3) As String
spam(0) = "hi there, how are you today?"
spam(1) = "I'd like to present to you the washing machine 9001."
spam(2) = "You have been nominated to win one of these!"
spam(3) = "Just make sure you don't break it"

For i = 0 To UBound(spam)
    Print spam(i); " -> "; SentenceType$(spam(i))
Next i

Function SentenceType$ (s As String)
    Select Case Right$(s, 1)
        Case "?"
            SentenceType$ = "Q"
        Case "!"
            SentenceType$ = "E"
        Case "."
            SentenceType$ = "S"
        Case Else
            SentenceType$ = "N"
    End Select
End Function
Output:
hi there, how are you today? -> Q
I'd like to present to you the washing machine 9001. -> S
You have been nominated to win one of these! -> E
Just make sure you don't break it -> N

QB64

The QBasic solution works without any changes.

Quite BASIC

Translation of: GW-BASIC
100 ARRAY S$
110 LET S$(1) = "hi there, how are you today?"
120 LET S$(2) = "I'd like to present to you the washing machine 9001."
130 LET S$(3) = "You have been nominated to win one of these!"
140 LET S$(4) = "Just make sure you don't break it"
150 FOR i = 1 TO 4
160   LET L$ = RIGHT(S$(i), 1)
170   IF L$ = "?" THEN LET t$ = "Q"
180   IF L$ = "!" THEN LET t$ = "E"
190   IF L$ = "." THEN LET t$ = "S"
200   IF L$ <> "?" AND L$ <> "!" AND L$ <> "." THEN LET t$ = "N"
210   PRINT S$(i); " -> "; t$
220 NEXT i

Run BASIC

Works with: Just BASIC
Works with: Liberty BASIC
dim spam$(3)
spam$(0) = "hi there, how are you today?"
spam$(1) = "I'd like to present to you the washing machine 9001."
spam$(2) = "You have been nominated to win one of these!"
spam$(3) = "Just make sure you don't break it"

for i = 0 to 3
    print spam$(i); " -> "; SentenceType$(spam$(i))
next i
end

function SentenceType$(s$)
    select case right$(s$, 1)
        case "?"
            SentenceType$ = "Q"
        case "!"
            SentenceType$ = "E"
        case "."
            SentenceType$ = "S"
        case else
            SentenceType$ = "N"
    end select
end function

True BASIC

Translation of: QBasic
DIM spam$(4)
LET spam$(1) = "hi there, how are you today?"
LET spam$(2) = "I'd like to present to you the washing machine 9001."
LET spam$(3) = "You have been nominated to win one of these!"
LET spam$(4) = "Just make sure you don't break it"

FUNCTION sentencetype$(s$)
    SELECT CASE (spam$(i))[LEN(spam$(i)):LEN(spam$(i))+1-1]
    CASE "?"
         LET sentencetype$ = "Q"
    CASE "!"
         LET sentencetype$ = "E"
    CASE "."
         LET sentencetype$ = "S"
    CASE ELSE
         LET sentencetype$ = "N"
    END SELECT
END FUNCTION

FOR i = 1 TO UBOUND(spam$)
    PRINT spam$(i); " -> "; sentencetype$(spam$(i))
NEXT i
END

XBasic

Works with: Windows XBasic
PROGRAM    "Determine sentence type"
VERSION    "0.0000"

DECLARE FUNCTION  Entry ()
DECLARE FUNCTION  SentenceType$ (s$)

FUNCTION Entry ()
    DIM spam$[4]
    spam$[1] = "hi there, how are you today?"
    spam$[2] = "I'd like to present to you the washing machine 9001."
    spam$[3] = "You have been nominated to win one of these!"
    spam$[4] = "Just make sure you don't break it"

    FOR i = 1 TO 4
        PRINT spam$[i]; " -> "; SentenceType$(spam$[i])
    NEXT i
END FUNCTION

FUNCTION SentenceType$ (s$)
    SELECT CASE RIGHT$(s$, 1)
        CASE "?":  RETURN "Q"
        CASE "!":  RETURN "E"
        CASE ".":  RETURN "S"
        CASE ELSE: RETURN "N"
    END SELECT
END FUNCTION
END PROGRAM

Yabasic

dim spam$(3)
spam$(0) = "hi there, how are you today?"
spam$(1) = "I'd like to present to you the washing machine 9001."
spam$(2) = "You have been nominated to win one of these!"
spam$(3) = "Just make sure you don't break it"

for i = 0 to arraysize(spam$(), 1)
    print spam$(i), " -> ", SentenceType$(spam$(i))
next i
end

sub SentenceType$ (s$)
    switch right$(s$, 1)
        case "?"
            return "Q"
        case "!"
            return "E"
        case "."
            return "S"
        default
            return "N"
    end switch
end sub

Bruijn

:import std/List .
:import std/Char .

determine [∅?0 '?' ([(0 =? '?' 'Q' (0 =? '.' 'S' (0 =? '!' 'E' 'N')))] _0)]

:test (determine empty) ('?')
:test (determine "hi there, how are you today?") ('Q')
:test (determine "I'd like to present to you the washing machine 9001.") ('S')
:test (determine "You have been nominated to win one of these!") ('E')
:test (determine "Just make sure you don't break it") ('N')

C++

#include <exception>
#include <iostream>
#include <string>
#include <vector>

char sentence_type(const std::string& sentence) {
	if ( sentence.empty() ) {
		throw std::invalid_argument("Cannot classify an empty sentence");
	}

	char result;
	const char last_character = sentence.back();
	switch (last_character) {
		case '?': result = 'Q'; break;
		case '.': result = 'S'; break;
		case '!': result = 'E'; break;
		default:  result = 'N'; break;
	};
	return result;
}

int main() {
	const std::vector<std::string> sentences = { "hi there, how are you today?",
									  	  	     "I'd like to present to you the washing machine 9001.",
												 "You have been nominated to win one of these!",
												 "Just make sure you don't break it" };

	for ( const std::string& sentence : sentences ) {
		std::cout << sentence << " -> " << sentence_type(sentence) << std::endl;
	}
}
hi there, how are you today? -> Q
I'd like to present to you the washing machine 9001. -> S
You have been nominated to win one of these! -> E
Just make sure you don't break it -> N

CLU

% This iterator takes a string and yields one of 'E', 'Q',
% 'S' or 'N' for every sentence found.
% Because sentences are separated by punctuation, only the
% last one can be 'N'.

sentence_types = iter (s: string) yields (char)
    own punct: string := "!?."  % relevant character classes
    own space: string := " \t\n"
    own types: string := "EQS"  % sentence type characters
    
    prev_punct: bool := false   % whether the previous character was punctuation
    last_punct: int := 0        % index of last punctuation character encountered
    sentence: bool := true      % whether there are words since the last punctuation
    
    for c: char in string$chars(s) do
        pu: int := string$indexc(c, punct)
        sp: int := string$indexc(c, space)
        if pu ~= 0 then
            prev_punct := true
            last_punct := pu 
        elseif sp ~= 0 then
            if prev_punct then
                % a space after punctuation means a sentence has ended here
                yield(types[last_punct])
                sentence := false
            end
            prev_punct := false
            sentence := false
        else
            sentence := true
        end
    end
    
    % handle the last sentence
    if prev_punct then yield(types[last_punct])
    elseif sentence then yield('N')
    end
end sentence_types

% Test
start_up = proc ()
    po: stream := stream$primary_output()
    test: string := 
        "hi there, how are you today? I'd like to " ||
        "present to you the washing machine 9001. You " ||
        "have been nominated to win one of these! Just " ||
        "make sure you don't break it" 

    % print the type of each sentence
    for c: char in sentence_types(test) do  
        stream$putc(po, c)
    end
end start_up
Output:
QSEN

Dart

Translation of: GW-BASIC
void main() {
  List<String> spam = [
    "hi there, how are you today?",
    "I'd like to present to you the washing machine 9001.",
    "You have been nominated to win one of these!",
    "Just make sure you don't break it"
  ];

  for (var s in spam) {
    print('$s -> ${sentenceType(s)}');
  }
}

String sentenceType(String s) {
  String lastChar = s[s.length - 1];
  if (lastChar == '?') return 'Q';
  if (lastChar == '!') return 'E';
  if (lastChar == '.') return 'S';
  return 'N';
}

Delphi

Works with: Delphi version 6.0


const TestStrings = 'hi there, how are you today? I''''d like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don''''t break it';

procedure AnalyzeSentenceType(Memo: TMemo; S: string);
{Extract sentences from string and analyze terminating punctuation}
var I: integer;
var Sent,SType: string;
begin
Sent:='';
for I:=1 to Length(S) do
	begin
	Sent:=Sent+S[I];
	{Look terminating char or condition}
	if (S[I] in ['?','!','.']) or (I>=Length(S)) then
		begin
		{If found, determine sentence type}
		case Sent[Length(Sent)] of
		 '?': SType:=' (Q)';
		 '!': SType:=' (E)';
		 '.': SType:=' (S)';
		 else SType:=' (N)';
		end;
		{Display it}
		Memo.Lines.Add(Trim(Sent)+SType);
		Sent:='';
		end;
	end;
end;


procedure TestSentenceTypes(Memo: TMemo);
{Analyze some test sentences}
begin
AnalyzeSentenceType(Memo, TestStrings);
end;
Output:
hi there, how are you today? (Q)
I''d like to present to you the washing machine 9001. (S)
You have been nominated to win one of these! (E)
Just make sure you don''t break it (N)

EasyLang

func$ stype s$ .
   h$ = substr s$ len s$ 1
   ind = strpos "?!." h$ mod1 4
   return substr "QESN" ind 1
.
txt$[] = [ "hi there, how are you today?" "I'd like to present to you the washing machine 9001." "You have been nominated to win one of these!" "Just make sure you don't break it" ]
for t$ in txt$[]
   print t$ & " -> " & stype t$
.
Output:
hi there, how are you today? -> Q
I'd like to present to you the washing machine 9001. -> S
You have been nominated to win one of these! -> E
Just make sure you don't break it -> N

Emacs Lisp

(defun get-last-character (str)
  "Return the last character of STR."
  (let ((str-length))
    (setq str-length (length str))
    (substring str (- str-length 1) str-length)))

(defun classify-sentence (str)
  "Classify the type of sentence based on final punctuation."
  (let ((last-character (get-last-character str)))
    (cond ((string= last-character ".") (format "S - %s" str))
          ((string= last-character "!") (format "E - %s" str))
          ((string= last-character "?") (format "Q - %s" str))
          (t (format "N - %s" str)))))

(defun classify-multiple-sentences (str)
  "Classify each sentence as Q, S, E, or N."
  ;; sentence boundary is defined as:
  ;;   a period (full stop), exclamation point/mark, or question mark
  ;;   followed by one space
  ;;   followed by a capital letter
  ;; while the above will work for this exercise, it won't
  ;; work in other situations. See the Perl code in this section
  ;; for cases that the above will not cover.
  (let ((regex-sentence-boundary "\\([.?!]\\) \\([[:upper:]]\\)"))
    ;; split the text into list of individual sentences
    (dolist (one-sentence (split-string (replace-regexp-in-string regex-sentence-boundary "\\1\n\\2"  str) "\n"))
      ;; classify each sentence
      (insert (format "\n%s" (classify-sentence one-sentence))))))

To run the Emacs Lisp code, evaluate the following:

(classify-multiple-sentences "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it")

Output:
Q - hi there, how are you today?
S - I'd like to present to you the washing machine 9001.
E - You have been nominated to win one of these!
N - Just make sure you don't break it


Epoxy

const SentenceTypes: {
	["?"]:"Q",
	["."]:"S",
	["!"]:"E"
}

fn DetermineSentenceType(Char)
	return SentenceTypes[Char]||"N"
cls

fn GetSentences(Text)
	var Sentences: [],
		Index: 0,
		Length: #Text
	loop i:0;i<Length;i+:1 do
		var Char: string.subs(Text,i,1)
		var Type: DetermineSentenceType(Char)
		if Type != "N" || i==Length-1 then
			log(string.sub(Text,Index,i+1)+" ("+Type+")")
			Index:i+2;
		cls
	cls
cls

GetSentences("hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it")
Output:
hi there, how are you today? (Q)
I'd like to present to you the washing machine 9001. (S)
You have been nominated to win one of these! (E)
Just make sure you don't break it (N)

Factor

This program attempts to prevent common abbreviations from ending sentences early. It also tries to handle parenthesized sentences and implements an additional type for exclamatory questions (EQ).

Works with: Factor version 0.99 2021-06-02
USING: combinators io kernel regexp sequences sets splitting
wrap.strings ;

! courtesy of https://www.infoplease.com/common-abbreviations

CONSTANT: common-abbreviations {
    "A.B." "abbr." "Acad." "A.D." "alt." "A.M." "Assn."
    "at. no." "at. wt." "Aug." "Ave." "b." "B.A." "B.C." "b.p."
    "B.S." "c." "Capt." "cent." "co." "Col." "Comdr." "Corp."
    "Cpl." "d." "D.C." "Dec." "dept." "dist." "div." "Dr." "ed."
    "est." "et al." "Feb." "fl." "gal." "Gen." "Gov." "grad."
    "Hon." "i.e." "in." "inc." "Inst." "Jan." "Jr." "lat."
    "Lib." "long." "Lt." "Ltd." "M.D." "Mr." "Mrs." "mt." "mts."
    "Mus." "no." "Nov." "Oct." "Op." "pl." "pop." "pseud." "pt."
    "pub." "Rev." "rev." "R.N." "Sept." "Ser." "Sgt." "Sr."
    "St." "uninc." "Univ." "U.S." "vol." "vs." "wt."
}

: sentence-enders ( str -- newstr )
    R/ \)/ "" re-replace
    " " split harvest
    unclip-last swap
    [ common-abbreviations member? ] reject
    [ last ".!?" member? ] filter
    swap suffix ;

: serious? ( str -- ? ) last CHAR: . = ;
: neutral? ( str -- ? ) last ".!?" member? not ;
: mixed? ( str -- ? ) "?!" intersect length 2 = ;
: exclamation? ( str -- ? ) last CHAR: ! = ;
: question? ( str -- ? ) last CHAR: ? = ;

: type ( str -- newstr )
    {
        { [ dup serious? ] [ drop "S" ] }
        { [ dup neutral? ] [ drop "N" ] }
        { [ dup mixed? ] [ drop "EQ" ] }
        { [ dup exclamation? ] [ drop "E" ] }
        { [ dup question? ] [ drop "Q" ] }
        [ drop "UNKNOWN" ]
    } cond ;

: sentences ( str -- newstr )
    sentence-enders [ type ] map "|" join ;

: show ( str -- )
    dup sentences " -> " glue 60 wrap-string print ;

"Hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it" show
nl
"(There was nary a mouse stirring.) But the cats were going
bonkers!" show
nl
"\"Why is the car so slow?\" she said." show
nl
"Hello, Mr. Anderson!" show
nl
"Are you sure?!?! How can you know?" show
Output:
Hi there, how are you today? I'd like to present to you the
washing machine 9001. You have been nominated to win one of
these! Just make sure you don't break it -> Q|S|E|N

(There was nary a mouse stirring.) But the cats were going
bonkers! -> S|E

"Why is the car so slow?" she said. -> S

Hello, Mr. Anderson! -> E

Are you sure?!?! How can you know? -> EQ|Q

Go

Translation of: Wren
package main

import (
    "fmt"
    "strings"
)

func sentenceType(s string) string {
    if len(s) == 0 {
        return ""
    }
    var types []string
    for _, c := range s {
        if c == '?' {
            types = append(types, "Q")
        } else if c == '!' {
            types = append(types, "E")
        } else if c == '.' {
            types = append(types, "S")
        }
    }
    if strings.IndexByte("?!.", s[len(s)-1]) == -1 {
        types = append(types, "N")
    }
    return strings.Join(types, "|")
}

func main() {
    s := "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it"
    fmt.Println(sentenceType(s))
}
Output:
Q|S|E|N

Java

import java.util.List;

public final class DetermineSentenceType {

	public static void main(String[] aArgs) {
		List<String> sentences = List.of( "hi there, how are you today?",
										  "I'd like to present to you the washing machine 9001.",
										  "You have been nominated to win one of these!",
										  "Just make sure you don't break it" );

		for ( String sentence : sentences ) {
			System.out.println(sentence + " -> " + sentenceType(sentence));
		}
	}
	
	private static char sentenceType(String aSentence) {
		if ( aSentence.isEmpty() ) {
			throw new IllegalArgumentException("Cannot classify an empty sentence");
		}
		
		final char lastCharacter = aSentence.charAt(aSentence.length() - 1);
		return switch (lastCharacter) {
			case '?' -> 'Q';
			case '.' -> 'S';
			case '!' -> 'E';
			default  -> 'N';
		};		
	}	
	
}
Output:
hi there, how are you today? -> Q
I'd like to present to you the washing machine 9001. -> S
You have been nominated to win one of these! -> E
Just make sure you don't break it -> N

jq

Works with: jq

Works with gojq, the Go implementation of jq

The following parses sentences with embedded quotations naively, so that for example the sentence "He asked 'How are you?'." results in: Q S

# Input: a string
# Output: a stream of sentence type indicators
def sentenceTypes:
  def trim: sub("^ +";"") | sub(" +$";"");
  def parse:
    capture("(?<s>[^?!.]*)(?<p>[?!.])(?<remainder>.*)" )
    // {p:"", remainder:""};
  def encode:
    if   . == "?" then "Q"
    elif . == "!" then "E"
    elif . == "." then "S"
    else "N"
    end;
  trim
  | select(length>0)
  | parse
  | (.p | encode), (.remainder | sentenceTypes);

def s: "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it";

s | sentenceTypes
Output:
Q
S
E
N

Julia

const text = """
Hi there, how are you today? I'd like to present to you the washing machine 9001.
You have been nominated to win one of these! Just make sure you don't break it"""

haspunctotype(s) = '.' in s ? "S" : '!' in s ? "E" : '?' in s ? "Q" : "N"

text = replace(text, "\n" => " ")
parsed = strip.(split(text, r"(?:(?:(?<=[\?\!\.])(?:))|(?:(?:)(?=[\?\!\.])))"))
isodd(length(parsed)) && push!(parsed, "")  # if ends without pnctuation
for i in 1:2:length(parsed)-1
    println(rpad(parsed[i] * parsed[i + 1], 52),  " ==> ", haspunctotype(parsed[i + 1]))
end
Output:
Hi there, how are you today?                         ==> Q
I'd like to present to you the washing machine 9001. ==> S
You have been nominated to win one of these!         ==> E
Just make sure you don't break it                    ==> N

Lua

text = "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it"
p2t = { [""]="N", ["."]="S", ["!"]="E", ["?"]="Q" }
for s, p in text:gmatch("%s*([^%!%?%.]+)([%!%?%.]?)") do
  print(s..p..":  "..p2t[p])
end
Output:
hi there, how are you today?:  Q
I'd like to present to you the washing machine 9001.:  S
You have been nominated to win one of these!:  E
Just make sure you don't break it:  N

Nim

type SentenceType {.pure.} = enum Q, E, S, N

func sentenceType(s: string): SentenceType =
  ## Return the type of a sentence.
  if s.len == 0: return
  result = case s[^1]
           of '?': Q
           of '!': E
           of '.': S
           else: N

iterator sentences(text: string): string =
  ## Cut a text into sentences.
  var sentence = ""
  for ch in text:
    if ch == ' ' and sentence.len == 0: continue
    sentence.add ch
    if ch in "?!.":
      yield sentence
      sentence.reset()
  if sentence.len > 0:
    yield sentence


const Text = "hi there, how are you today? " &
             "I'd like to present to you the washing machine 9001. " &
             "You have been nominated to win one of these!" &
             "Just make sure you don't break it"

for sentence in Text.sentences():
  echo sentence, " → ", sentenceType(sentence)
Output:
hi there, how are you today? → Q
I'd like to present to you the washing machine 9001. → S
You have been nominated to win one of these! → E
Just make sure you don't break it → N

PascalABC.NET

function SentenceType(s: string): char;
begin
  case s[^1] of
    '?': Result := 'Q';
    '!': Result := 'E';
    '.': Result := 'S';
    else Result := 'N';
  end;
end;

begin
  var ss := Arr('hi there, how are you today?',
    'I''d like to present to you the washing machine 9001.',
    'You have been nominated to win one of these!',
    'Just make sure you don''t break it');
  foreach var s in ss do
    Println(s,'->',SentenceType(s));
end.
Output:
hi there, how are you today? -> Q
I'd like to present to you the washing machine 9001. -> S
You have been nominated to win one of these! -> E
Just make sure you don't break it -> N

Perl

use strict;
use warnings;
use feature 'say';
use Lingua::Sentence;

my $para1 = <<'EOP';
hi there, how are you today? I'd like to present to you the washing machine
9001. You have been nominated to win one of these! Just make sure you don't
break it
EOP

my $para2 = <<'EOP';
Just because there are punctuation characters like "?", "!" or especially "."
present, it doesn't necessarily mean you have reached the end of a sentence,
does it Mr. Magoo? The syntax highlighting here for Perl isn't bad at all.
EOP

my $splitter = Lingua::Sentence->new("en");
for my $text ($para1, $para2) {
  for my $s (split /\n/, $splitter->split( $text =~ s/\n//gr ) {
    print "$s| ";
    if    ($s =~ /!$/)  { say 'E' }
    elsif ($s =~ /\?$/) { say 'Q' }
    elsif ($s =~ /\.$/) { say 'S' }
    else                { say 'N' }
  }
}
Output:
hi there, how are you today?| Q
I'd like to present to you the washing machine 9001.| S
You have been nominated to win one of these!| E
Just make sure you don't break it.| N
Just because there are punctuation characters like "?", "!" or especially "." present, it doesn't necessarily mean you have reached the end of a sentence, does it Mr. Magoo?| Q
The syntax highlighting here for Perl isn't bad at all.| S

Phix

with javascript_semantics
constant s = `hi there, how are you today? I'd like to present 
to you the washing machine 9001. You have been nominated to win 
one of these! Just make sure you don't break it`
sequence t = split_any(trim(s),"?!."),
         u = substitute_all(s,t,repeat("|",length(t))),
         v = substitute_all(u,{"|?","|!","|.","|"},"QESN"),
         w = join(v,'|')
?w
Output:
"Q|S|E|N"

Prolog

Translation of: GW-BASIC
Works with: SWI Prolog
spam([
    "hi there, how are you today?",
    "I'd like to present to you the washing machine 9001.",
    "You have been nominated to win one of these!",
    "Just make sure you don't break it"
]).

sentence_type(S, 'Q') :- sub_atom(S, _, 1, 0, '?'), !.
sentence_type(S, 'E') :- sub_atom(S, _, 1, 0, '!'), !.
sentence_type(S, 'S') :- sub_atom(S, _, 1, 0, '.'), !.
sentence_type(_, 'N').

print_sentences([]).
print_sentences([H|T]) :-
    sentence_type(H, Type),
    format('~w -> ~w~n', [H, Type]),
    print_sentences(T).

main :-
    spam(Sentences),
    print_sentences(Sentences).

Python

import re

txt = """
Hi there, how are you today? I'd like to present to you the washing machine 9001.
You have been nominated to win one of these! Just make sure you don't break it"""

def haspunctotype(s):
    return 'S' if '.' in s else 'E' if '!' in s else 'Q' if '?' in s else 'N'

txt = re.sub('\n', '', txt)
pars = [s.strip() for s in re.split("(?:(?:(?<=[\?\!\.])(?:))|(?:(?:)(?=[\?\!\.])))", txt)]
if len(pars) % 2:
    pars.append('')  # if ends without punctuation
for i in range(0, len(pars)-1, 2):
    print((pars[i] + pars[i + 1]).ljust(54), "==>", haspunctotype(pars[i + 1]))
Output:
Hi there, how are you today?                           ==> Q
I'd like to present to you the washing machine 9001.   ==> S
You have been nominated to win one of these!           ==> E
Just make sure you don't break it                      ==> N


Or for more generality, and an alternative to hand-crafted regular expressions:

'''Grouping and tagging by final character of string'''

from functools import reduce
from itertools import groupby


# tagGroups :: Dict -> [String] -> [(String, [String])]
def tagGroups(tagDict):
    '''A list of (Tag, SentenceList) tuples, derived
       from an input text and a supplied dictionary of
       tags for each of a set of final punctuation marks.
    '''
    def go(sentences):
        return [
            (tagDict.get(k, 'Not punctuated'), list(v))
            for (k, v) in groupby(
                sorted(sentences, key=last),
                key=last
            )
        ]
    return go


# sentenceSegments :: Chars -> String -> [String]
def sentenceSegments(punctuationChars):
    '''A list of sentences delimited by the supplied
       punctuation characters, where these are followed
       by spaces.
    '''
    def go(s):
        return [
            ''.join(cs).strip() for cs
            in splitBy(
                sentenceBreak(punctuationChars)
            )(s)
        ]
    return go


# sentenceBreak :: Chars -> (Char, Char) -> Bool
def sentenceBreak(finalPunctuation):
    '''True if the first of two characters is a final
       punctuation mark and the second is a space.
    '''
    def go(a, b):
        return a in finalPunctuation and " " == b
    return go


# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''Join, segmentation, tags'''

    tags = {'!': 'E', '?': 'Q', '.': 'S'}

    # Joined by spaces,
    sample = ' '.join([
        "Hi there, how are you today?",
        "I'd like to present to you the washing machine 9001.",
        "You have been nominated to win one of these!",
        "Might it be possible to add some challenge to this task?",
        "Feels as light as polystyrene filler.",
        "But perhaps substance isn't the goal!",
        "Just make sure you don't break off before the"
    ])

    # segmented by punctuation,
    sentences = sentenceSegments(
        tags.keys()
    )(sample)

    # and grouped under tags.
    for kv in tagGroups(tags)(sentences):
        print(kv)


# ----------------------- GENERIC ------------------------

# last :: [a] -> a
def last(xs):
    '''The last element of a non-empty list.'''
    return xs[-1]


# splitBy :: (a -> a -> Bool) -> [a] -> [[a]]
def splitBy(p):
    '''A list split wherever two consecutive
       items match the binary predicate p.
    '''
    # step :: ([[a]], [a], a) -> a -> ([[a]], [a], a)
    def step(acp, x):
        acc, active, prev = acp

        return (acc + [active], [x], x) if p(prev, x) else (
            (acc, active + [x], x)
        )

    # go :: [a] -> [[a]]
    def go(xs):
        if 2 > len(xs):
            return xs
        else:
            h = xs[0]
            ys = reduce(step, xs[1:], ([], [h], h))
            # The accumulated sublists, and the final group.
            return ys[0] + [ys[1]]

    return go


# MAIN ---
if __name__ == '__main__':
    main()
Output:
('E', ['You have been nominated to win one of these!', "But perhaps substance isn't the goal!"])
('S', ["I'd like to present to you the washing machine 9001.", 'Feels as light as polystyrene filler.'])
('Q', ['Hi there, how are you today?', 'Might it be possible to add some challenge to this task?'])
('Not punctuated', ["Just make sure you don't break off before the"])

Racket

#lang racket

(define input "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it")

(define sentence-types #hash((#\. . "S") (#\? . "Q") (#\! . "E")))
(define punctuation (hash-keys sentence-types))

(let ([characters (string->list input)])
  (for ([i characters])
    (when (member i punctuation)
      (printf "~a|" (hash-ref sentence-types i))))
  (unless (member (last characters) punctuation)
    (printf "N")))
Output:
Q|S|E|N

Raku

use Lingua::EN::Sentence;

my $paragraph = q:to/PARAGRAPH/;
hi there, how are you today? I'd like to present to you the washing machine
9001. You have been nominated to win one of these! Just make sure you don't
break it


Just because there are punctuation characters like "?", "!" or especially "."
present, it doesn't necessarily mean you have reached the end of a sentence,
does it Mr. Magoo? The syntax highlighting here for Raku isn't the best.
PARAGRAPH

say join "\n\n", $paragraph.&sentences.map: {
    /(<:punct>)$/;
    $_ ~ ' | ' ~ do
    given $0 {
        when '!' { 'E' };
        when '?' { 'Q' };
        when '.' { 'S' };
        default  { 'N' };
    }
}
Output:
hi there, how are you today? | Q

I'd like to present to you the washing machine
9001. | S

You have been nominated to win one of these! | E

Just make sure you don't
break it | N

Just because there are punctuation characters like "?", "!" or especially "."
present, it doesn't necessarily mean you have reached the end of a sentence,
does it Mr. Magoo? | Q

The syntax highlighting here for Raku isn't the best. | S

Refal

$ENTRY Go {
    , 'hi there, how are you today? I\'d like to '
      'present to you the washing machine 9001. '
      'You have been nominated to win one of these! '
      'Just make sure you don\'t break it': e.Sentences
    = <Prout <SentenceTypes e.Sentences>>;
};

SentenceTypes {
    e.X '?' = Q;
    e.X '? ' e.Y = Q <SentenceTypes e.Y>;
    e.X '.' = S;
    e.X '. ' e.Y = S <SentenceTypes e.Y>;
    e.X '!' = E;
    e.X '! ' e.Y = E <SentenceTypes e.Y>;
    e.X = N;
}
Output:
Q S E N

Ring

see "working..." + nl
sType = []
sent = "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! How do you like this washing machine? Buy it, don't hesitate! You will be satisfied with it. Just make sure you don't break it"

ind = 1
while true
      pos = substring(sent,"?",ind)
      if pos > 0
         add(sType,pos)
         ind = pos+1
      else
         exit
      ok
end

ind = 1
while true
      pos = substring(sent,"!",ind)
      if pos > 0
         add(sType,pos)
         ind = pos+1
      else
         exit
      ok
end

ind = 1
while true
      pos = substring(sent,".",ind)
      if pos > 0
         add(sType,pos)
         ind = pos+1
      else
         exit
      ok
end

if pos < len(sent)
   neut = "N"
else
   neut = ""
ok

sType = sort(sType)

text = ""
for n = 1 to len(sType)
    if sent[sType[n]] = "?"
       text = text + "Q" + "|"
    ok
    if sent[sType[n]] = "!"
       text = text + "E" + "|"
    ok
    if sent[sType[n]] = "."
       text = text + "S" + "|"
    ok
next
see text + neut  + nl
see "done..." + nl

func substring str,substr,n
	newstr=right(str,len(str)-n+1)
	nr = substr(newstr, substr)
	if nr = 0
		return 0
	else
		return n + nr -1
	ok
Output:
working...
Q|S|E|Q|E|S|N
done...

RPL

Works with: Halcyon Calc version 4.2.8
≪ OVER SIZE → str seps len 
  ≪ 1 CF { 0 } 1 len FOR j 
     IF seps str j DUP SUB POS THEN 
        j + IF j len == THEN 1 SF END 
     END NEXT 
     IF 1 FC? THEN len + END 
     { } SWAP 1 OVER SIZE 1 - FOR j 
       str OVER j GETI 1 + ROT ROT 
       GET SUB ROT SWAP + SWAP 
     NEXT DROP 
≫ ≫ 'PARSE' STO

≪ "?!." SWAP OVER PARSE "QES" → seps sents types
  ≪ 1 sents SIZE FOR j 
       sents j GET seps
       IF OVER DUP SIZE DUP SUB POS THEN 
          "=" types LAST DUP SUB + 
       ELSE "=N" END + 
     NEXT
≫ ≫ 'STYPE' STO
"hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it" STYPE
Output:
4: "hi there, how are you today?=Q"
3: " I'd like to present to you the washing machine 9001.=S"
2: " You have been nominated to win one of these!=E"
1: " Just make sure you don't break it=N"

V (Vlang)

Translation of: Go
fn sentence_type(s string) string {
    if s.len == 0 {
        return ""
    }
    mut types := []string{}
    for c in s.split('') {
        if c == '?' {
            types << "Q"
        } else if c == '!' {
            types << "E"
        } else if c == '.' {
            types << "S"
        }
    }
    if s[s.len-1..s.len].index_any('?!.') == -1 {
        types << "N"
    }
    return types.join("|")
}
 
fn main() {
    s := "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it"
    println(sentence_type(s))
}
Output:
Q|S|E|N

Wren

var sentenceType = Fn.new { |s|
    if (s.count == 0) return ""
    var types = []
    for (c in s) {
        if (c == "?") {
            types.add("Q")
        } else if (c == "!") {
            types.add("E")
        } else if (c == ".") {
            types.add("S")
        }
    }
    if (!"?!.".contains(s[-1])) types.add("N")
    return types.join("|")
}

var s = "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it"
System.print(sentenceType.call(s))
Output:
Q|S|E|N


Library: Wren-pattern
Library: Wren-iterate

The following alternative version takes the simplistic view that (unless they end the final sentence of the paragraph) ?, ! or . will only end a sentence if they're immediately followed by a space. This of course is nonsense, given the way English is written nowadays, but it's probably an improvement on the first version without the need to search through an inevitably incomplete list of abbreviations.

import "./pattern" for Pattern
import "./iterate" for Indexed

var map = { "?": "Q", "!": "E", ".": "S", "": "N" }
var p = Pattern.new("[? |! |. ]")
var paras = [
    "hi there, how are you today? I'd like to present to you the washing machine 9001. You have been nominated to win one of these! Just make sure you don't break it",
    "hi there, how are you on St.David's day (isn't it a holiday yet?), Mr.Smith? I'd like to present to you (well someone has to win one!) the washing machine 900.1. You have been nominated by Capt.Johnson('?') to win one of these! Just make sure you (or Mrs.Smith) don't break it. By the way, what the heck is an exclamatory question!?"
]

for (para in paras) {
    para = para.trim()
    var sentences = p.splitAll(para)
    var endings = p.findAll(para).map { |m| m.text[0] }.toList
    var lastChar = sentences[-1][-1]
    if ("?!.".contains(lastChar)) {
        endings.add(lastChar)
        sentences[-1] = sentences[-1][0...-1]
    } else {
        endings.add("")
    }
    for (se in Indexed.new(sentences)) {
        var ix = se.index
        var sentence = se.value
        System.print("%(map[endings[ix]]) <- %(sentence + endings[ix])")
    }
    System.print()
}
Output:
Q <- hi there, how are you today?
S <- I'd like to present to you the washing machine 9001.
E <- You have been nominated to win one of these!
N <- Just make sure you don't break it

Q <- hi there, how are you on St.David's day (isn't it a holiday yet?), Mr.Smith?
S <- I'd like to present to you (well someone has to win one!) the washing machine 900.1.
E <- You have been nominated by Capt.Johnson('?') to win one of these!
S <- Just make sure you (or Mrs.Smith) don't break it.
Q <- By the way, what the heck is an exclamatory question!?

XPL0

include xpllib; \for StrLen
int  Sentence, N, Len;
char Str;
[Sentence:= ["hi there, how are you today?",
             "I'd like to present to you the washing machine 9001.",
             "You have been nominated to win one of these!",
             "Just make sure you don't break it"];
for N:= 0 to 3 do
    [Str:= Sentence(N);
    Len:= StrLen(Str);
    case Str(Len-1) of
      ^!: ChOut(0, ^E);
      ^?: ChOut(0, ^Q);
      ^.: ChOut(0, ^S)
    other ChOut(0, ^N);
    if N < 3 then ChOut(0, ^|);
    ];
]
Output:
Q|S|E|N