string1 = input("Please enter a string.")
string2 = input("Please enter a second string.")

//Comparing two strings for exact equality

if string1 == string2 then
    print "Strings are equal."
end if

//Comparing two strings for inequality

if string1 != string2 then
    print "Strings are NOT equal."
end if

//Comparing two strings to see if one is lexically ordered before than the other

if string1 > string2 then
    print string1 + " is lexically ordered AFTER " + string2

//Comparing two strings to see if one is lexically ordered after than the other

else if string1 < string2 then
    print string1 + " is lexically ordered BEFORE " + string2
end if

//How to achieve case sensitive comparisons

//Comparing two strings for exact equality (case sensitive)
if string1 == string2 then
    print "Strings are equal. (case sensitive)"
end if

//Comparing two strings for inequality (case sensitive)
if string1 != string2 then
    print "Strings are NOT equal. (case sensitive)"
end if

//How to achieve case insensitive comparisons within the language

//Comparing two strings for exact equality (case insensitive)
if string1.lower == string2.lower then
    print "Strings are equal. (case insensitive)"
end if

//Comparing two strings for inequality (case insensitive)
if string1.lower != string2.lower then
    print "Strings are NOT equal. (case insensitive)"
end if


string msg = "hello";
msg += " world";
write(msg +"\n");


Cat: procedure options (main);
   declare s character (100) varying;
   s = 'dust ';
   s ||= 'bowl';
   put (s);
end Cat;


To run:
Start up.
Put "abc" into a string.
Append "123" to the string.
Write the string to the console.
Wait for the escape key.
Shut down.


\def\addtomacro#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\foo{Hello}
Initial: \foo

\addtomacro\foo{ world!}
Appended: \foo
\bye


S$ = "Hello"
S$ = S$ + " Wo" ;by referencing the string twice
S$ + "rld!"     ;by referencing the string once
If OpenConsole()
  PrintN(S$)

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


#!/usr/bin/env python
# -*- coding: utf-8 -*- #

str = "12345678";
str += "9!";
print(str)


def compare(a, b)
	println format("\n%s is of type %s and %s is of type %s", a, type(a), b, type(b))
	if a < b
		println format("%s is strictly less than %s", a, b)
	end
	if a <= b
		println format("%s is less than or equal to %s", a, b)
	end
	if a > b
		println format("%s is strictly greater than %s", a, b)
	end
	if a >= b
		println format("%s is greater than or equal to %s", a, b)
	end
	if a = b
		println format("%s is equal to %s", a, b)
	end
	if a != b
		println format("%s is not equal to %s", a, b)
	end
end

compare("YUP", "YUP")
compare("BALL", "BELL")
compare("24", "123")
compare(24, 123)
compare(5.0, 5)


animal = 'dog'
if animal = 'cat' then
  say animal "is lexically equal to cat"
if animal \= 'cat' then
  say animal "is not lexically equal cat"
if animal > 'cat' then
  say animal "is lexically higher than cat"
if animal < 'cat' then
  say animal "is lexically lower than cat"
if animal >= 'cat' then
  say animal "is not lexically lower than cat"
if animal <= 'cat' then
  say animal "is not lexically higher than cat"
/* The above comparative operators do not consider
   leading and trailing whitespace when making comparisons. */
if '  cat  ' = 'cat' then
  say "this will print because whitespace is stripped"

/* To consider all whitespace in a comparison
   we need to use strict comparative operators */

if '  cat  ' == 'cat' then
  say "this will not print because comparison is strict"


import strutils

var s1: string = "The quick brown"
var s2: string = "The Quick Brown"
echo("== : ", s1 == s2)
echo("!= : ", s1 != s2)
echo("< : ", s1 < s2)
echo("<= : ", s1 <= s2)
echo("> : ", s1 > s2)
echo(">= : ", s1 >= s2)
# cmpIgnoreCase(a, b) => 0 if a == b; < 0 if a < b; > 0 if a > b
echo("cmpIgnoreCase :", s1.cmpIgnoreCase s2)


"abcd" "abcd" ==
"abcd" "abce" <>
"abcd" "abceed" <=
"abce" "abcd" >
"abcEEE" toUpper "ABCeee" toUpper ==


s$ = "String"
s$ = s$ + " append"
PRINT s$


  [ tuck take swap join swap put ] is append ( [ s --> )

  $ "L'homme qui attend de voir un canard roti voler "   temp put
  $ "dans sa bouche doit attendre tres, tres longtemps." temp append
  temp take echo$


;there is no built-in way to set! append in racket
(define mystr "foo")
(set! mystr (string-append mystr " bar"))
(displayln mystr)

;but you can create a quick macro to solve that problem
(define-syntax-rule (set-append! str value)
  (set! str (string-append str value)))

(define mymacrostr "foo")
(set-append! mymacrostr " bar")
(displayln mystr)


my $str = "foo";
$str ~= "bar";
say $str;


set a = "Hello"
set b = " World"
set c = a.b
echo c


aString1 = "Welcome to the "
aString2 = "Ring Programming Language"
aString3 = aString1 + aString2
see aString3


set "$str1" to "Hello "
inc "$str1" by "world!"
* "&$str1&"
end


a=.array~of('A 1','B 2','a 3','b 3','A 5')
a~sortwith(.caselesscomparator~new)
Do i=1 To 5
  Say a[i]
  End


use v5.16;  # ...for fc(), which does proper Unicode casefolding.
            # With older Perl versions you can use lc() as a poor-man's substitute.

sub compare {
    my ($a, $b) = @_;
    my $A = "'$a'";
    my $B = "'$b'";

    print "$A and $B are lexically equal.\n"     if $a eq $b;
    print "$A and $B are not lexically equal.\n" if $a ne $b;

    print "$A is lexically before $B.\n"         if $a lt $b;
    print "$A is lexically after $B.\n"          if $a gt $b;

    print "$A is not lexically before $B.\n"     if $a ge $b;
    print "$A is not lexically after $B.\n"      if $a le $b;

    print "The lexical relationship is: ", $a cmp $b, "\n";
    print "The case-insensitive lexical relationship is: ", fc($a) cmp fc($b), "\n";
    print "\n";
}

compare('Hello', 'Hello');
compare('5', '5.0');
compare('perl', 'Perl');


s = "Hello wo"
s += "rld" # new string object
s << "!"   # mutates in place, same object
puts s


use std::ops::Add;

fn main(){
    let hello = String::from("Hello world");
    println!("{}", hello.add("!!!!"));
}


  var d = "Hello" // Mutables are discouraged     //> d  : String = Hello
  d += ", World!" // var contains a totally new re-instantiationed String

  val s = "Hello" // Immutables are recommended   //> s  : String = Hello
  val s1 = s + s                                  //> s1  : String = HelloHello
  val f2 = () => " !" //Function assigned to variable
                                                  //> f2  : () => String = <function0>
  println(s1 + f2());                             //> HelloHello !


$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: str is "12345678";
  begin
    str &:= "9!";
    writeln(str);
  end func;


     s = "Hello"
     s = s ", World!"
     OUTPUT = s
END


sca s="Ars Longa"
sca s=s+" Vita Brevis"
di s

Ars Longa Vita Brevis


var s = "foo"              // "foo"
s += "bar"                 // "foobar"
print(s)                   // "foobar"
s.appendContentsOf("baz")  // "foobarbaz"
print(s)                   // "foobarbaz"


with javascript_semantics
string name="Pete"
if name=="pete" then ?"The strings are equal" end if
if name!="pete" then ?"The strings are not equal" end if
if name<"pete" then ?"name is lexically first" end if
if name>"pete" then ?"name is lexically last" end if
if upper(name)=upper("pete") then ?"case insensitive match" end if
if match("pete",lower(name)) then ?"petes in there somewhere" end if


main =>
  S1 = "abc",
  S2 = "def",
  S1 == S2, % -> false.
  S1 != S2, % -> true.
  S1 @< S2, % -> true. Is S1 lexicographically less than S1?
  S1 @> S2, % -> false.
  to_lowercase(S1) == to_lowercase(S2), % -> false.

  "1234" @> "123",  % -> true. lexical comparison
  "1234" @< 12342222, % -> false. No coersion is done. Numbers are always ordered before strings

  123 < 1234. % -> true   '<' is used only for numbers


(setq
   str= =
   str< <
   str> > )

(println
   (str= (lowc "Foo") (lowc "foo") (lowc "fOO"))
   (str= "f" "foo")
   (str= "foo" "foo" "foo")
   (str= "" "") )

(println
   (str< "abc" "def")
   (str> "abc" "def")
   (str< "" "")
   (str< "12" "45") )

(bye)


set s "he"
set s "${s}llo wo";   # The braces distinguish varname from text to concatenate
append s "rld"
puts $s


#lang transd

MainModule: {
    _start: (λ
        (with s1 "aaa" s2 "bbb" s3 "ccc"
            (+= s1 s2 s3)
            (textout s1))
    )
}


decl string str
set str "hello "

# append "world" to str
set str (+ str "world")

# outputs "hello world"
out str endl console


void main() {
  string x = "foo";
  x += "bar\n";
  print(x);
}


Function StringAppend()
Dim s As String
s = "foo"
s = s & "bar"
Debug.Print s
End Function


s = "Rosetta"
s = s & " Code"
WScript.StdOut.Write s


mut s:= 'foo'
s += 'bar'
println(s)

foo := 'foo'
bar := 'bar'
foobar := '$foo$bar'
println(foobar)


"a" -lt "b"  # lower than
"a" -eq "b"  # equal
"a" -gt "b"  # greater than
"a" -le "b"  # lower than or equal
"a" -ne "b"  # not equal
"a" -ge "b"  # greater than or equal


Macro StrTest(Check,tof)
  Print("Test "+Check+#TAB$)
  If tof=1 : PrintN("true") : Else : PrintN("false") : EndIf
EndMacro

Procedure.b StrBool_eq(a$,b$)   :   ProcedureReturn Bool(a$=b$)             :   EndProcedure
Procedure.b StrBool_n_eq(a$,b$) :   ProcedureReturn Bool(a$<>b$)            :   EndProcedure
Procedure.b StrBool_a(a$,b$)    :   ProcedureReturn Bool(a$>b$)             :   EndProcedure
Procedure.b StrBool_b(a$,b$)    :   ProcedureReturn Bool(a$<b$)             :   EndProcedure
Procedure.b NumBool_eq(a$,b$)   :   ProcedureReturn Bool(Val(a$)=Val(b$))   :   EndProcedure
Procedure.b NumBool_n_eq(a$,b$) :   ProcedureReturn Bool(Val(a$)<>Val(b$))  :   EndProcedure
Procedure.b NumBool_a(a$,b$)    :   ProcedureReturn Bool(Val(a$)>Val(b$))   :   EndProcedure
Procedure.b NumBool_b(a$,b$)    :   ProcedureReturn Bool(Val(a$)<Val(b$))   :   EndProcedure

Procedure Compare(a$,b$,cs.b=1,num.b=0)
  If Not cs : a$=UCase(a$) : b$=UCase(b$) : EndIf
  PrintN("a = "+a$) : PrintN("b = "+b$)
  If Not num  :   StrTest(" a=b ",StrBool_eq(a$,b$))     :   Else  :   StrTest(" a=b ",NumBool_eq(a$,b$))     :   EndIf
  If Not num  :   StrTest(" a<>b ",StrBool_n_eq(a$,b$))  :   Else  :   StrTest(" a<>b ",NumBool_n_eq(a$,b$))  :   EndIf
  If Not num  :   StrTest(" a>b ",StrBool_a(a$,b$))      :   Else  :   StrTest(" a>b ",NumBool_a(a$,b$))      :   EndIf
  If Not num  :   StrTest(" a<b ",StrBool_b(a$,b$))      :   Else  :   StrTest(" a<b ",NumBool_b(a$,b$))      :   EndIf
EndProcedure

If OpenConsole()
  PrintN("String comparison - ")
  a$="Abcd" : b$="abcd"
  PrintN(#CRLF$+"- case sensitive:")
  Compare(a$,b$)
  PrintN(#CRLF$+"- case insensitive:")
  Compare(a$,b$,0)
  a$="1241" : b$="222"
  PrintN(#CRLF$+"- num-string; lexically compared:")
  Compare(a$,b$)
  PrintN(#CRLF$+"- num-string; numerically compared:")
  Compare(a$,b$,1,1)
  Input()
EndIf


var s = "Hello, "
s = s + "world!"
System.print(s)


include xpllib;
char A, B, C(80);
[A:= "Hello, ";
B:= "world!";
StrCopy(C, A);
StrCat(C, B);
Text(0, C);
]


var s="foo";
s.append("bar"); //-->new string "foobar", var s unchanged
s+="bar";        //-->new string "foobar", var s modifed to new value

s=Data(Void,"foo");	// byte blob/character blob/text editor buffer
s.append("bar");  // or s+="bar"
s.text; //-->"foobar"


def compare(a, b):
    print("\n%r is of type %r and %r is of type %r"
          % (a, type(a), b, type(b)))
    if a <  b:      print('%r is strictly less than  %r' % (a, b))
    if a <= b:      print('%r is less than or equal to %r' % (a, b))
    if a >  b:      print('%r is strictly greater than  %r' % (a, b))
    if a >= b:      print('%r is greater than or equal to %r' % (a, b))
    if a == b:      print('%r is equal to %r' % (a, b))
    if a != b:      print('%r is not equal to %r' % (a, b))
    if a is b:      print('%r has object identity with %r' % (a, b))
    if a is not b:  print('%r has negated object identity with %r' % (a, b))

compare('YUP', 'YUP')
compare('BALL', 'BELL')
compare('24', '123')
compare(24, 123)
compare(5.0, 5)


Dim As String String1, String2

' direct string comparison using case sensitive
String1 = "GWbasic"
String2 = "QuickBasic"
If String1 = String2 Then Print String1; " is equal to "; String2 Else Print String1; " is NOT egual to  "; String2
String1 = "gWbasic"
String2 = "GWBasic"
If String1 = String2 Then Print String1; " is equal to "; String2 Else Print String1; " is NOT egual to  "; String2

' direct string comparison using case insensitive
If UCase$(String1) = UCase$(String2) Then Print String1; " is equal to "; String2; Else Print String1; " is NOT egual to  "; String2;
Print " case insensitive"
String1 = "GwBasiC"
String2 = "GWBasic"
If LCase$(String1) = LCase$(String2) Then Print String1; " is equal to "; String2; Else Print String1; " is NOT egual to  "; String2;
Print " case insensitive"

' lexical order
String1 = "AAAbbb"
String2 = "AaAbbb"
If String1 > String2 Then Print String1; " is after "; String2 Else Print String1; " is before "; String2

' number in string format comparison
String1 = "0123"
String2 = "5"
' lexical order
If String1 > String2 Then Print String1; " is after "; String2 Else Print String1; " is before "; String2
' value order
If Val(String1) > Val(String2) Then Print String1; " is bigger than "; String2 Else Print String1; " is lower "; String2

Print "QB64, like QBasic, has native coercive/allomorphic operators for string type variable"
End


/O> ( compare two strings for equality )
... $ "abc" $ "xyz" =
... echo ( 0 = false, 1 = true )
...
0
Stack empty.

/O> ( compare two strings for inequality )
... $ "abc" $ "xyz" !=
... echo ( 0 = false, 1 = true )
...
1
Stack empty.

//O> ( compare two strings to see if one is lexically ordered before the other )
... $ "abc" $ "xyz" $<
... echo ( 0 = false, 1 = true )
...
1
Stack empty.

/O> ( compare two strings to see if one is lexically ordered after the other )
... $ "abc" $ "xyz" $>
... echo ( 0 = false, 1 = true )
...
1
Stack empty.

/O> ( for case insensitive, convert both strings to the same case )
... [ $ "" swap witheach [ upper join ] ] is upper$ ( $ --> $ )
... $ "AbC" upper$  $ "aBc" upper$  =
... echo ( 0 = false, 1 = true )
...
1
Stack empty.

/O> ( Numeric strings are not treated differently to other strings.     )
... ( Lexical ordering uses QACSFOT rather than ASCII/Unicode ordering. )
    (                                                                   )
... (     "Quackery Arbitrary Character Sequence For Ordered Text"      )
... (         0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrS           )
... (         sTtUuVvWwXxYyZz()[]{}<>~=+-*/^\|_.,:;?!'"`%@&#$           )
...

Stack empty.


compare <- function(a, b)
{
  cat(paste(a, "is of type", class(a), "and", b, "is of type", class(b), "\n"))

  if (a < b) cat(paste(a, "is strictly less than", b, "\n"))
  if (a <= b) cat(paste(a, "is less than or equal to", b, "\n"))
  if (a > b) cat(paste(a, "is strictly greater than", b, "\n"))
  if (a >= b) cat(paste(a, "is greater than or equal to", b, "\n"))
  if (a == b) cat(paste(a, "is equal to", b, "\n"))
  if (a != b) cat(paste(a, "is not equal to", b, "\n"))

  invisible()
}

compare('YUP', 'YUP')
compare('BALL', 'BELL')
compare('24', '123')
compare(24, 123)
compare(5.0, 5)


#lang racket

;; Comparing two strings for exact equality
(string=? "foo" "foo")

;; Comparing two strings for inequality
(not (string=? "foo" "bar"))

;; Comparing two strings to see if one is lexically ordered before than the other
(string<? "abc" "def")

;; Comparing two strings to see if one is lexically ordered after than the other
(string>? "def" "abc")

;; How to achieve both case sensitive comparisons and case insensitive comparisons within the language
(string-ci=? "foo" "FOO")


sub compare($a,$b) {
    my $A = "{$a.WHAT.^name} '$a'";
    my $B = "{$b.WHAT.^name} '$b'";

    if $a eq $b { say "$A and $B are lexically equal" }
    if $a ne $b { say "$A and $B are not lexically equal" }

    if $a gt $b { say "$A is lexically after $B" }
    if $a lt $b { say "$A is lexically before than $B" }

    if $a ge $b { say "$A is not lexically before $B" }
    if $a le $b { say "$A is not lexically after $B" }

    if $a === $b { say "$A and $B are identical objects" }
    if $a !=== $b { say "$A and $B are not identical objects" }

    if $a eqv $b { say "$A and $B are generically equal" }
    if $a !eqv $b { say "$A and $B are not generically equal" }

    if $a before $b { say "$A is generically after $B" }
    if $a after $b { say "$A is generically before $B" }

    if $a !after $b { say "$A is not generically before $B" }
    if $a !before $b { say "$A is not generically after $B" }

    say "The lexical relationship of $A and $B is { $a leg $b }" if $a ~~ Stringy;
    say "The generic relationship of $A and $B is { $a cmp $b }";
    say "The numeric relationship of $A and $B is { $a <=> $b }" if $a ~~ Numeric;
    say '';
}

compare 'YUP', 'YUP';
compare 'BALL', 'BELL';
compare 24, 123;
compare 5.1, 5;
compare 5.1e0, 5 + 1/10;


set a = "Hello"
set b = "World"
if a == b
' a is equal to b (case sensitive)
end if
if lower(a) == lower(b)
' a is equal to b (case insensitive)
end if
if a !== b
' a is not equal to b (case sensitive)
end if
if lower(a) !== lower(b)
' a is not equal to b (case insensitive)
end if
if a << b
' a is lexically first to b (case sensitive)
end if
if lower(a) << lower(b)
' a is lexically first to b (case insensitive)
end if
if a >> b
' a is lexically after b (case sensitive)
end if
if lower(a) >> Lower(b)
' a is lexically after b (case insensitive)
end if


/*REXX program shows  different ways to  compare  two character strings.*/
say 'This is an '      word('ASCII EBCDIC', 1+(1=='f1'))        ' system.'
say
      cat = 'cat'
   animal = 'dog'
if animal =  cat  then say $(animal) "is lexically equal to"        $(cat)
if animal \= cat  then say $(animal) "is not lexically equal to"    $(cat)
if animal >  cat  then say $(animal) "is lexically higher than"     $(cat)
if animal <  cat  then say $(animal) "is lexically lower than"      $(cat)
if animal >  cat  then say $(animal) "is not lexically lower than"  $(cat)
if animal <  cat  then say $(animal) "is not lexically higher than" $(cat)

                      /*──── [↑]  The above comparative operators don't */
                      /*────consider any leading and/or trailing white- */
                      /*────space when making comparisons, but the case */
                      /*────is honored  (uppercase, lowercase).         */

fatcat='  cat  '      /*pad the cat with leading and trailing blanks.   */
if fatcat =  cat  then say $(fatcat) " is equal to"                 $(cat)

                      /*────To consider any whitespace in a comparison, */
                      /*────we need to use strict comparative operators.*/

if fatcat == cat  then say $(fatcat) "is strictly equal to"         $(cat)

                      /*────To perform caseless comparisons, the easiest*/
                      /*────method would be to uppercase a copy of both */
                      /*────operands.  Uppercasing is only done for the */
                      /*────Latin (or Roman) alphabet in REXX.    [↓]   */
kat='cAt'
if caselessComp(cat,kat)  then  say $(cat) 'and' $(kat) "are equal caseless"
exit                                   /*stick a fork in it, we're done.*/
/*──────────────────────────────────$ subroutine────────────────────────*/
$:  return '──►'arg(1)'◄──'            /*bracket the string with ──►α◄──*/
/*──────────────────────────────────CASELESSCOMP subroutine─────────────*/
caselessComp:  procedure;  arg a,b     /*ARG  uppercases the A & B args.*/
               return a==b             /*if exactly equal, return  1.   */


   if s1 = s2
      See "The strings are equal"
   ok
   if not (s1 = s2)
      See "The strings are not equal"
   ok
   if strcmp(s1,s2) > 0
      see "s2 is lexically ordered before than s1"
   ok
   if strcmp(s1,s2) < 0
      see "s2 is lexically ordered after than s1"
   ok

To achieve case insensitive comparisons, we should use Upper() or Lower() functions:

   if Upper(s1) = Upper(s2)
      see "The strings are equal"
   ok


set "$str1" to "annoy"
set "$str2" to "annoy"
: "loop"
if "$str1" === "$str2" then "case_equal"
if "$str1" = "$str2" then "equal"
if "$str1" > "$str2" then "greater_than"
if "$str1" < "$str2" then "less_than"
end

: "case_equal"
* "&$str1& is case equal to &$str2&"
set "$str2" to "ANNOY"
goto "loop"

: "equal"
* "&$str1& is equal to &$str2&"
set "$str2" to "allow"
wait for 100
goto "loop"

: "greater_than"
* "&$str1& is lexicographically greater than &$str2&"
set "$str1" to "aardvark"
wait for 100
goto "loop"

: "less_than"
* "&$str1& is lexicographically less than &$str2&"
end


method_names = [:==,:!=, :>, :>=, :<, :<=, :<=>, :casecmp]
[["YUP", "YUP"], ["YUP", "Yup"], ["bot","bat"], ["aaa", "zz"]].each do |str1, str2|
  method_names.each{|m| puts "%s %s %s\t%s" % [str1, m, str2, str1.send(m, str2)]}
  puts
end


a$	= "dog"
b$	= "cat"
if a$ =  b$ then print "the strings are equal" 			' test for equalitY
if a$ <> b$ then print "the strings are not equal" 		' test for inequalitY
if a$ >  b$ then print a$;" is lexicallY higher than ";b$ 	' test for lexicallY higher
if a$ <  b$ then print a$;" is lexicallY lower than ";b$ 	' test for lexicallY lower
if a$ <= b$ then print a$;" is not lexicallY higher than ";b$
if a$ >= b$ then print a$;" is not lexicallY lower than ";b$
end


use std::ascii::AsciiExt; // for case insensitives only

fn main() {
    // only same types can be compared
    // String and String or &str and &str
    // exception: strict equality and inequality also work on &str and String
    let a: &str = "abc";
    let b: String = "Bac".to_owned();

    // Strings are coerced to &str when borrowed and needed
    if a == b { println!("The strings are equal") }
    if a != b { println!("The strings are not equal") }
    if a  > &b { println!("The first string is lexically after the second") }
    if a  < &b { println!("The first string is lexically before the second") }
    if a >= &b { println!("The first string is not lexically before the second") }
    if a <= &b { println!("The first string is not lexically after the second") }

    // case-insensitives:

    // equality
    // this avoids new allocations
    if a.eq_ignore_ascii_case(&b) { println!("Both strings are equal when ignoring case") }

    // everything else, create owned Strings, then compare as above
    let a2 = a.to_ascii_uppercase();
    let b2 = b.to_ascii_uppercase();

    // repeat checks
}


object Compare extends App {
  def compare(a: String, b: String) {
    if (a == b) println(s"'$a' and '$b' are lexically equal.")
    else println(s"'$a' and '$b' are not lexically equal.")

    if (a.equalsIgnoreCase(b)) println(s"'$a' and '$b' are case-insensitive lexically equal.")
    else println(s"'$a' and '$b' are not case-insensitive lexically equal.")

    if (a.compareTo(b) < 0) println(s"'$a' is lexically before '$b'.")
    else if (a.compareTo(b) > 0) println(s"'$a' is lexically after '$b'.")

    if (a.compareTo(b) >= 0) println(s"'$a' is not lexically before '$b'.")
    if (a.compareTo(b) <= 0) println(s"'$a' is not lexically after '$b'.")

    println(s"The lexical relationship is: ${a.compareTo(b)}")
    println(s"The case-insensitive lexical relationship is: ${a.compareToIgnoreCase(b)}\n")
  }

  compare("Hello", "Hello")
  compare("5", "5.0")
  compare("java", "Java")
  compare("ĴÃVÁ", "ĴÃVÁ")
  compare("ĴÃVÁ", "ĵãvá")
}


;; Comparing two strings for exact equality
(string=? "hello" "hello")

;; Comparing two strings for inequality
(not (string=? "hello" "Hello"))

;; Checking if the first string is lexically ordered before the second
(string<? "bar" "foo")

;; Checking if the first string is lexically ordered after the second
(string>? "foo" "bar")

;; case insensitive comparison
(string-ci=? "hello" "Hello")


$ include "seed7_05.s7i";

const proc: showComparisons (in string: a, in string: b) is func
  begin
    writeln("compare " <& literal(a) <& " with " <& literal(b) <&":");
    writeln("a = b  returns: " <& a = b);
    writeln("a <> b returns: " <& a <> b);
    writeln("a < b  returns: " <& a < b);
    writeln("a > b  returns: " <& a > b);
    writeln("a <= b returns: " <& a <= b);
    writeln("a >= b returns: " <& a >= b);
    writeln("compare(a, b)               returns: " <& compare(a, b));
    writeln("compare(lower(a), lower(b)) returns: " <& compare(a, b));
  end func;

const proc: main is func
  begin
    showComparisons("this", "that");
    showComparisons("that", "this");
    showComparisons("THAT", "That");
    showComparisons("this", "This");
    showComparisons("this", "this");
    showComparisons("the", "there");
    showComparisons("there", "the");
  end func;


var methods = %w(== != > >= < <= <=>)
for s1, s2 in [<YUP YUP>,<YUP Yup>,<bot bat>,<aaa zz>] {
    methods.each{|m| "%s %s %s\t%s\n".printf(s1, m, s2, s1.(m)(s2))}
    print "\n"
}


methods := #(= ~= > >= < <= sameAs: ).
#(
    ('YUP' 'YUP')
    ('YUP' 'yup')
) pairsDo:[:s1 :s2 |
    methods do:[:m |
        '%-20s\t%s\n' printf:
            {
                ('(%S %s %S)' printf:{s1 . m . s2}) .
                (s1 perform:m with:s2)
            } on:Stdout
    ].
    Stdout cr
]


      s1 = 'mnopqrs'
      s2 = 'mnopqrs'
      s3 = 'mnopqr'
      s4 = 'nop'
      s5 = 'nOp'

      OUTPUT = 'Case sensitive comparisons:'
      OUTPUT = LEQ(s1, s2) s1 ' and ' s2 ' are equal (LEQ).'
      OUTPUT = IDENT(s1, s2) s1 ' and ' s2 ' are equal (IDENT).'

      OUTPUT =
      OUTPUT = LNE(s1, s3) s1 ' and ' s3 ' are not equal (LNE).'
      OUTPUT = ~LEQ(s1, s3) s1 ' and ' s3 ' are not equal (~LEQ).'
      OUTPUT = DIFFER(s1, s3) s1 ' and ' s3 ' are not equal (DIFFER).'

      OUTPUT =
      OUTPUT = LGE(s1, s3) s1 ' is greater than or equal to ' s3 ' (LGE).'
      OUTPUT = LLE(s3, s1) s3 ' is less than or equal to ' s1 ' (LLE).'

      OUTPUT =
      OUTPUT = LGT(s4, s1) s4 ' is greater than ' s1 ' (LGT).'
      OUTPUT = LLT(s1, s4) s1 ' is less than ' s4 ' (LLT).'

      OUTPUT =
      OUTPUT = "Case insensitive comparison:"
      OUTPUT = LEQ(s4, REPLACE(s5, &UCASE, &LCASE)) s4 ' and ' s5 ' are equal.'

      OUTPUT =
      OUTPUT = 'String and numeric conversions and comparisons:'
      OUTPUT = EQ('1234', 1234) '"1234" and 1234 are equal (coerce to integer).'
      OUTPUT = LEQ('1234', 1234) '"1234" and 1234 are equal (coerce to string).'
      OUTPUT =
      OUTPUT = GT('1234', 1233) '"1234" is greater than 1233 (numeric comparison).'
      OUTPUT = LT('1233', 1234) '"1233" is less than 1234 (numeric comparison).'
END


map String.compare [ ("one","one"),
   ("one","two"),
   ("one","Two"),
   ("one",String.map Char.toLower "Two")
   ] ;

val it = [EQUAL, LESS, GREATER, LESS]: order list

"one" <> "two" ;
val it = true: bool


func compare (a: String, b: String) {
  if a == b {
    println("'\(a)' and '\(b)' are lexically equal.")
  }
  if a != b {
    println("'\(a)' and '\(b)' are not lexically equal.")
  }

  if a < b {
    println("'\(a)' is lexically before '\(b)'.")
  }
  if a > b {
    println("'\(a)' is lexically after '\(b)'.")
  }

  if a >= b {
    println("'\(a)' is not lexically before '\(b)'.")
  }
  if a <= b {
    println("'\(a)' is not lexically after '\(b)'.")
  }
}
compare("cat", "dog")


$a -> \(when <=$b> do '$a; equals $b;' ! \) -> !OUT::write

$a -> \(when <~=$b> do '$a; not equal to $b;' ! \) -> !OUT::write

$a -> \(when <..$b> do '$a; lexically less or equal to $b;' ! \) -> !OUT::write

$a -> \(when <$b..> do '$a; lexically greater or equal to $b;' ! \) -> !OUT::write

$a -> \(when <..~$b> do '$a; lexically less than $b;' ! \) -> !OUT::write

$a -> \(when <$b~..> do '$a; lexically greater than $b;' ! \) -> !OUT::write

$a -> \(when <'$b;'> do '$a; matches the regex $b;' ! \) -> !OUT::write

$a -> \(when <'(?i)$b;'> do '$a; matches the regex $b; case insensitively' ! \) -> !OUT::write


if {$a eq $b} {
    puts "the strings are equal"
}
if {$a ne $b} {
    puts "the strings are not equal"
}


#!/bin/sh

A=Bell
B=Ball

# Traditional test command implementations test for equality and inequality
# but do not have a lexical comparison facility
if [ $A = $B ] ; then
  echo 'The strings are equal'
fi
if [ $A != $B ] ; then
  echo 'The strings are not equal'
fi

# All variables in the shell are strings, so numeric content cause no lexical problems
# 0 , -0 , 0.0 and 00 are all lexically different if tested using the above methods.

# However this may not be the case if other tools, such as awk are the slave instead of test.


void main() {
  var s1 = "The quick brown";
  var s2 = "The Quick Brown";
  stdout.printf("== : %s\n", s1 == s2 ? "true" : "false");
  stdout.printf("!= : %s\n", s1 != s2 ? "true" : "false");
  stdout.printf("<  : %s\n", s1 <  s2 ? "true" : "false");
  stdout.printf("<= : %s\n", s1 <= s2 ? "true" : "false");
  stdout.printf(">  : %s\n", s1 >  s2 ? "true" : "false");
  stdout.printf(">= : %s\n", s1 >= s2 ? "true" : "false");
}


fn main() {
    c := "cat"
    d := "dog"
    if c == d {
        println('$c is bytewise identical to $d')
    }
    if c != d {
        println('$c is bytewise different from $d')
    }
    if c > d {
        println('$c is lexically bytewise greater than $d')
    }
    if c < d {
        println('$c is lexically bytewise less than $d')
    }
    if c >= d {
        println('$c is lexically bytewise greater than or equal to $d')
    }
    if c <= d {
        println('$c is lexically bytewise less than or equal to $d')
    }
}


== 'example1' 'example2' -- io.writeln io.stdout; # Test for exact equality.
== 'example1' 'example2' -> ! -- io.writeln io.stdout; # Test for inequality.
< 'example1' 'example2' -- io.writeln io.stdout; # Test for lexical before.
> 'example1' 'example2' -- io.writeln io.stdout; # Test for lexical after.

# Case insensitive equality check by converting both to lowercase.
let str => import 'strings';
== (str.lower 'eXaMpLe') (str.lower 'ExAmPlE') -- io.writeln io.stdout;

# This is false. Strings are not coerced to numbers and vice-versa.
== '3' 3 -- io.writeln io.stdout;


import "/str" for Str

var compareStrings = Fn.new { |a, b, sens|
    System.write("Comparing '%(a)' and '%(b)', ")
    var c
    var d
    if (sens) {
        System.print("case sensitively:")
        c = a
        d = b
    } else {
        System.print("case insensitively:")
        c = Str.lower(a)
        d = Str.lower(b)
    }
    System.print("     %(a) <  %(b) -> %(Str.lt(c, d))")
    System.print("     %(a) >  %(b) -> %(Str.gt(c, d))")
    System.print("     %(a) == %(b) -> %(c == d)")
    System.print("     %(a) != %(b) -> %(c != d)")
    System.print("     %(a) <= %(b) -> %(Str.le(c, d))")
    System.print("     %(a) >= %(b) -> %(Str.ge(c, d))")
    System.print()
}

compareStrings.call("cat", "dog", true)
compareStrings.call("Rat", "RAT", true)
compareStrings.call("Rat", "RAT", false)
compareStrings.call("1100", "200", true)


include xpllib;         \provides StrLen, ToLower, StrCopy, and StrCmp

proc StrToLower(A, B);
char A, B, I;
for I:= 0 to StrLen(B) do A(I):= ToLower(B(I));

proc CompareStrings(A, B, Sens);
char A, B, Sens, C, D;
[C:= Reserve(StrLen(A)+1);
 D:= Reserve(StrLen(B)+1);
Text(0, "Comparing "); Text(0, A); Text(0, " and "); Text(0, B); Text(0, ", ");
if Sens then
        [Text(0, "case sensitively:^m^j");
        StrCopy(C, A);
        StrCopy(D, B);
        ]
else    [Text(0, "case insensitively:^m^j");
        StrToLower(C, A);
        StrToLower(D, B);
        ];
Text(0, "    ");  Text(0, A);  Text(0, " <  ");  Text(0, B);  Text(0, " -> ");
Text(0, if StrCmp(C, D) < 0 then "true" else "false");  CrLf(0);
Text(0, "    ");  Text(0, A);  Text(0, " >  ");  Text(0, B);  Text(0, " -> ");
Text(0, if StrCmp(C, D) > 0 then "true" else "false");  CrLf(0);
Text(0, "    ");  Text(0, A);  Text(0, " =  ");  Text(0, B);  Text(0, " -> ");
Text(0, if StrCmp(C, D) = 0 then "true" else "false");  CrLf(0);
Text(0, "    ");  Text(0, A);  Text(0, " #  ");  Text(0, B);  Text(0, " -> ");
Text(0, if StrCmp(C, D) # 0 then "true" else "false");  CrLf(0);
Text(0, "    ");  Text(0, A);  Text(0, " <= ");  Text(0, B);  Text(0, " -> ");
Text(0, if StrCmp(C, D) <= 0 then "true" else "false");  CrLf(0);
Text(0, "    ");  Text(0, A);  Text(0, " >= ");  Text(0, B);  Text(0, " -> ");
Text(0, if StrCmp(C, D) >= 0 then "true" else "false");  CrLf(0);
CrLf(0);
];

[CompareStrings("cat", "dog", true);
 CompareStrings("Rat", "RAT", true);
 CompareStrings("Rat", "RAT", false);
 CompareStrings("1100", "200", true);
]


*        String length             06/07/2016
LEN      CSECT
         USING  LEN,15             base register
         LA     1,L'C              length of C
         XDECO  1,PG
         XPRNT  PG,12
         LA     1,L'H              length of H
         XDECO  1,PG
         XPRNT  PG,12
         LA     1,L'F              length of F
         XDECO  1,PG
         XPRNT  PG,12
         LA     1,L'D              length of D
         XDECO  1,PG
         XPRNT  PG,12
         LA     1,L'PG             length of PG
         XDECO  1,PG
         XPRNT  PG,12
         BR     14                 exit           length
C        DS     C                  character       1
H        DS     H                  half word       2
F        DS     F                  full word       4
D        DS     D                  double word     8
PG       DS     CL12               string         12
         END    LEN


GetStringLength: ;$00 and $01 make up the pointer to the string's base address.
                 ;(Of course, any two consecutive zero-page memory locations can fulfill this role.)
LDY #0           ;Y is both the index into the string and the length counter.

loop_getStringLength:
LDA ($00),y
BEQ exit
INY
JMP loop_getStringLength

exit:
RTS               ;string length is now loaded into Y.


GetStringLength:
; INPUT: A3 = BASE ADDRESS OF STRING
; RETURNS LENGTH IN D1 (MEASURED IN BYTES)
MOVE.L #0,D1

loop_getStringLength:

MOVE.B (A3)+,D0
CMP #0,D0
BEQ done
ADDQ.L #1,D1
BRA loop_getStringLength

done:
RTS


;INPUT: DS:SI = BASE ADDR. OF STRING
;TYPICALLY, MS-DOS USES $ TO TERMINATE STRINGS.
GetStringLength:
xor cx,cx      ;this takes fewer bytes to encode than "mov cx,0"
cld            ;makes string functions post-inc rather than post-dec.

loop_GetStringLength:
lodsb          ;equivalent of "mov al,[ds:si],inc si" except this doesn't alter the flags.
cmp '$'
je done        ;if equal, we're finished.
inc cx         ;add 1 to length counter. A null string will have a length of zero.
jmp loop_GetStringLength

done:
ret


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program stringLength64.s   */

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

/*********************************/
/* Initialized data              */
/*********************************/
.data
sMessResultByte:        .asciz "===Byte Length=== : @ \n"
sMessResultChar:        .asciz "===Character Length=== : @ \n"
szString1:              .asciz "møøse€"
szCarriageReturn:       .asciz "\n"

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                 // entry of program
    ldr x0,qAdrszString1
    bl affichageMess                  // display string
    ldr x0,qAdrszCarriageReturn
    bl affichageMess

    ldr x0,qAdrszString1
    mov x1,#0
1:                                    // loop compute length bytes
    ldrb w2,[x0,x1]
    cmp w2,#0
    cinc x1,x1,ne
    bne 1b

    mov x0,x1                         // result display
    ldr x1,qAdrsZoneConv
    bl conversion10                   // call decimal conversion
    ldr x0,qAdrsMessResultByte
    ldr x1,qAdrsZoneConv              // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess

    ldr x0,qAdrszString1
    mov x1,#0
    mov x3,#0
2:                                    // loop compute length characters
    ldrb w2,[x0,x1]
    cmp w2,#0
    beq 6f
    and x2,x2,#0b11100000             // 3 bytes ?
    cmp x2,#0b11100000
    bne 3f
    add x3,x3,#1
    add x1,x1,#3
    b 2b
3:
    and x2,x2,#0b11000000              // 2 bytes ?
    cmp x2,#0b11000000
    bne 4f
    add x3,x3,#1
    add x1,x1,#2
    b 2b
4:                                    // else 1 byte
    add x3,x3,#1
    add x1,x1,#1
    b 2b

6:
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl conversion10                   // call decimal conversion
    ldr x0,qAdrsMessResultChar
    ldr x1,qAdrsZoneConv              // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess
100:                                  // standard end of the program
    mov x0,0                          // return code
    mov x8,EXIT                       // request to exit program
    svc 0                             // perform the system call

qAdrszCarriageReturn:     .quad szCarriageReturn
qAdrsMessResultByte:      .quad sMessResultByte
qAdrsMessResultChar:      .quad sMessResultChar
qAdrszString1:            .quad szString1
qAdrsZoneConv:            .quad sZoneConv
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


PROC Test(CHAR ARRAY s)
  PrintF("Length of ""%S"" is %B%E",s,s(0))
RETURN

PROC Main()
  Test("Hello world!")
  Test("")
RETURN


package {

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.utils.ByteArray;

    public class StringByteLength extends Sprite {

        public function StringByteLength() {
            if ( stage ) _init();
            else addEventListener(Event.ADDED_TO_STAGE, _init);
        }

        private function _init(e:Event = null):void {
            var s1:String = "The quick brown fox jumps over the lazy dog";
            var s2:String = "𝔘𝔫𝔦𝔠𝔬𝔡𝔢";
            var s3:String = "José";

            var b:ByteArray = new ByteArray();
            b.writeUTFBytes(s1);
            trace(b.length);  // 43

            b.clear();
            b.writeUTFBytes(s2);
            trace(b.length);  // 28

            b.clear();
            b.writeUTFBytes(s3);
            trace(b.length);  // 5
        }

    }

}


Str    : String := "Hello World";
Length : constant Natural := Str'Size / 8;


BITS bits := bits pack((TRUE, TRUE, FALSE, FALSE)); # packed array of BOOL #
BYTES bytes := bytes pack("Hello, world"); # packed array of CHAR #
print((
  "BITS and BYTES are fixed width:", new line,
  "bits width:", bits width, ", max bits: ", max bits, ", bits:", bits, new line,
  "bytes width: ",bytes width, ", UPB:",UPB STRING(bytes), ", string:", STRING(bytes),"!", new line
))


String myString = 'abcd';
System.debug('Size of String', myString.length());


/* ARM assembly Raspberry PI  */
/*  program stringLength.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 */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"

/*********************************/
/* Initialized data              */
/*********************************/
.data
sMessResultByte:        .asciz "===Byte Length=== : @ \n"
sMessResultChar:        .asciz "===Character Length=== : @ \n"
szString1:          .asciz "møøse€"
szCarriageReturn:   .asciz "\n"

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                 @ entry of program
    ldr r0,iAdrszString1
    bl affichageMess                  @ display string
    ldr r0,iAdrszCarriageReturn
    bl affichageMess

    ldr r0,iAdrszString1
    mov r1,#0
1:                                    @ loop compute length bytes
    ldrb r2,[r0,r1]
    cmp r2,#0
    addne r1,#1
    bne 1b

    mov r0,r1                         @ result display
    ldr r1,iAdrsZoneConv
    bl conversion10                   @ call decimal conversion
    ldr r0,iAdrsMessResultByte
    ldr r1,iAdrsZoneConv              @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess

    ldr r0,iAdrszString1
    mov r1,#0
    mov r3,#0
2:                                    @ loop compute length characters
    ldrb r2,[r0,r1]
    cmp r2,#0
    beq 6f
    and r2,#0b11100000                @ 3 bytes ?
    cmp r2,#0b11100000
    bne 3f
    add r3,#1
    add r1,#3
    b 2b
3:
    and r2,#0b11000000                @ 2 bytes ?
    cmp r2,#0b11000000
    bne 4f
    add r3,#1
    add r1,#2
    b 2b
4:                                    @ else 1 byte
    add r3,#1
    add r1,#1
    b 2b

6:
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl conversion10                   @ call decimal conversion
    ldr r0,iAdrsMessResultChar
    ldr r1,iAdrsZoneConv              @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess
100:                                  @ standard end of the program
    mov r0, #0                        @ return code
    mov r7, #EXIT                     @ request to exit program
    svc #0                            @ perform the system call

iAdrszCarriageReturn:     .int szCarriageReturn
iAdrsMessResultByte:      .int sMessResultByte
iAdrsMessResultChar:      .int sMessResultChar
iAdrszString1:            .int szString1
iAdrsZoneConv:            .int sZoneConv
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"


str: "Hello World"

print ["length =" size str]


w=length("Hello, world!")      # static string example
x=length("Hello," s " world!") # dynamic string example
y=length($1)                   # input field example
z=length(s)                    # variable name example


"HELLO, WORLD"→Str1
Disp length(Str1)▶Dec,i


PRINT "Bytelen of 'hello': ", LEN("hello")
PRINT "Charlen of 'hello': ", ULEN("hello")

PRINT "Bytelen of 'møøse': ", LEN("møøse")
PRINT "Charlen of 'møøse': ", ULEN("møøse")

PRINT "Bytelen of '𝔘𝔫𝔦𝔠𝔬𝔡𝔢': ", LEN("𝔘𝔫𝔦𝔠𝔬𝔡𝔢")
PRINT "Charlen of '𝔘𝔫𝔦𝔠𝔬𝔡𝔢': ", ULEN("𝔘𝔫𝔦𝔠𝔬𝔡𝔢")


@echo off
setlocal enabledelayedexpansion
call :length %1 res
echo length of %1 is %res%
goto :eof

:length
set str=%~1
set cnt=0
:loop
if "%str%" equ "" (
	set %2=%cnt%
	goto :eof
	)
set str=!str:~1!
set /a cnt = cnt + 1
goto loop


      INPUT text$
      PRINT LEN(text$)


(ByteLength=
  length
.   @(!arg:? [?length)
  & !length
);

out$ByteLength$𝔘𝔫𝔦𝔠𝔬𝔡𝔢


#include <string.h>

int main(void)
{
  const char *string = "Hello, world!";
  size_t length = strlen(string);

  return 0;
}


string s = "Hello, world!";
int characterLength = s.Length;


#include <string> // (not <string.h>!)
using std::string;

int main()
{
  string s = "Hello, world!";
  string::size_type length = s.length(); // option 1: In Characters/Bytes
  string::size_type size = s.size();     // option 2: In Characters/Bytes
  // In bytes same as above since sizeof(char) == 1
  string::size_type bytes = s.length() * sizeof(string::value_type);
}


import StdEnv

strlen :: String -> Int
strlen string = size string

Start = strlen "Hello, world!"


(def utf-8-octet-length #(-> % (.getBytes "UTF-8") count))
(map utf-8-octet-length  ["møøse" "𝔘𝔫𝔦𝔠𝔬𝔡𝔢" "J\u0332o\u0332s\u0332e\u0301\u0332"]) ; (7 28 14)

(def utf-16-octet-length (comp (partial * 2) count))
(map utf-16-octet-length ["møøse" "𝔘𝔫𝔦𝔠𝔬𝔡𝔢" "J\u0332o\u0332s\u0332e\u0301\u0332"]) ; (10 28 18)

(def code-unit-length count)
(map code-unit-length    ["møøse" "𝔘𝔫𝔦𝔠𝔬𝔡𝔢" "J\u0332o\u0332s\u0332e\u0301\u0332"]) ; (5 14 9)


<cfoutput>
<cfset str = "Hello World">
<cfset j = createObject("java","java.lang.String").init(str)>
<cfset t = j.getBytes()>
<p>#arrayLen(t)#</p>
</cfoutput>


(length (sb-ext:string-to-octets "Hello Wørld"))


MODULE TestLen;

	IMPORT Out;

	PROCEDURE DoCharLength*;
		VAR s: ARRAY 16 OF CHAR; len: INTEGER;
	BEGIN
		s := "møøse";
		len := LEN(s$);
		Out.String("s: "); Out.String(s); Out.Ln;
		Out.String("Length of characters: "); Out.Int(len, 0); Out.Ln
	END DoCharLength;

END TestLen.


import std.stdio;

void showByteLen(T)(T[] str) {
    writefln("Byte length: %2d - %(%02x%)",
             str.length * T.sizeof, cast(ubyte[])str);
}

void main() {
    string s1a = "møøse"; // UTF-8
    showByteLen(s1a);
    wstring s1b = "møøse"; // UTF-16
    showByteLen(s1b);
    dstring s1c = "møøse"; // UTF-32
    showByteLen(s1c);
    writeln();

    string s2a = "𝔘𝔫𝔦𝔠𝔬𝔡𝔢";
    showByteLen(s2a);
    wstring s2b = "𝔘𝔫𝔦𝔠𝔬𝔡𝔢";
    showByteLen(s2b);
    dstring s2c = "𝔘𝔫𝔦𝔠𝔬𝔡𝔢";
    showByteLen(s2c);
    writeln();

    string s3a = "J̲o̲s̲é̲";
    showByteLen(s3a);
    wstring s3b = "J̲o̲s̲é̲";
    showByteLen(s3b);
    dstring s3c = "J̲o̲s̲é̲";
    showByteLen(s3c);
}


!. len !encode!utf-8 "møøse"
!. len !encode!utf-8 "𝔘𝔫𝔦𝔠𝔬𝔡𝔢"


import extensions;

public program()
{
    var s := "Hello, world!";             // UTF-8 literal
    var ws := "Привет мир!"w;             // UTF-16 literal

    var s_length := s.Length;             // Number of UTF-8 characters
    var ws_length := ws.Length;           // Number of UTF-16 characters
    var u_length := ws.toArray().Length;    //Number of UTF-32 characters
}


open System.Text
let byte_length str = Encoding.UTF8.GetByteCount(str)


: string-byte-length ( string -- n ) [ code-point-length ] map-sum ;
: string-byte-length-2 ( string -- n ) utf8 encode length ;


fansh> c := "møøse"
møøse
fansh> c.toBuf.size   // find the byte length of the string in default (UTF8) encoding
7
fansh> c.toBuf.toHex  // display UTF8 representation
6dc3b8c3b87365
fansh> c.toBuf(Charset.utf16LE).size    // byte length in UTF16 little-endian
10
fansh> c.toBuf(Charset.utf16LE).toHex   // display as UTF16 little-endian
6d00f800f80073006500
fansh> c.toBuf(Charset.utf16BE).size    // byte length in UTF16 big-endian
10
fansh> c.toBuf(Charset.utf16BE).toHex   // display as UTF16 big-endian
006d00f800f800730065


CREATE s ," Hello world" \ create string "s"
s [email protected] ( -- length=11 )
s COUNT  ( addr len )   \ convert to a stack string, described below


' FB 1.05.0 Win64

Dim s As String      = "moose"  '' variable length ascii string
Dim f As String  * 5 = "moose"  '' fixed length ascii string (in practice a zero byte is appended)
Dim z As ZString * 6 = "moose"  '' fixed length zero terminated ascii string
Dim w As WString * 6 = "møøse"  '' fixed length zero terminated unicode string

' Variable length strings have a descriptor consisting of 3 Integers (12 bytes on 32 bit, 24 bytes on 64 bit systems)
' In order, the descriptor contains the address of the data, the memory currently used and the memory allocated

' In Windows, WString uses UCS-2 encoding (i.e. 2 bytes per character, surrogates are not supported)
' In Linux,   WString uses UCS-4 encoding (i.e. 4 bytes per character)

' The Len function always returns the length of the string in characters
' The SizeOf function returns the bytes used (by the descriptor in the case of variable length strings)

Print "s : " ; s, "Character Length : "; Len(s), "Byte Length : "; Len(s); "  (data)"
Print "s : " ; s, "Character Length : "; Len(s), "Byte Length : "; SizeOf(s); " (descriptor)"
Print "f : " ; f, "Character Length : "; Len(s), "Byte Length : "; SizeOf(f)
Print "z : " ; z, "Character Length : "; Len(s), "Byte Length : "; SizeOf(z)
Print "w : " ; w, "Character Length : "; Len(s), "Byte Length : "; SizeOf(w)
Print
Sleep


b = "𝔘𝔫𝔦𝔠𝔬𝔡𝔢"
length[stringToBytes[b, "UTF-8"]]


Length("abc");
# or same result with
Size("abc");


package main

import "fmt"

func main() {
    m := "møøse"
    u := "𝔘𝔫𝔦𝔠𝔬𝔡𝔢"
    j := "J̲o̲s̲é̲"
    fmt.Printf("%d %s % x\n", len(m), m, m)
    fmt.Printf("%d %s %x\n", len(u), u, u)
    fmt.Printf("%d %s % x\n", len(j), j, j)
}


import Data.Encoding
import Data.ByteString as B

strUTF8  :: ByteString
strUTF8  = encode UTF8  "Hello World!"

strUTF32 :: ByteString
strUTF32 = encode UTF32 "Hello World!"

strlenUTF8  = B.length strUTF8
strlenUTF32 = B.length strUTF32


U8 *string = "Hello, world!";
Print("%d\n", StrLen(string));


String s = "Hello, world!";
int byteCountUTF16 = s.getBytes("UTF-16").length; // Incorrect: it yields 28 (that is with the BOM)
int byteCountUTF16LE = s.getBytes("UTF-16LE").length; // Correct: it yields 26
int byteCountUTF8  = s.getBytes("UTF-8").length; // yields 13


var s = "Hello, world!";
var byteCount = s.length * 2; //26


$ cat String_length.jq
def describe:
   "length of \(.) is \(length)";

("J̲o̲s̲é̲", "𝔘𝔫𝔦𝔠𝔬𝔡𝔢") | describe


//Store length of hello world in length and print it
. length = "Hello World".length();


sizeof("Hello, world!") # gives 13
sizeof("Hellö, wørld!") # gives 15


    #"Hello, world!"
13
    #"Hëllo, world!"
13


// version 1.0.6
fun main(args: Array<String>) {
    val s = "José"
    println("The char length is ${s.length}")
    println("The byte length is ${Character.BYTES * s.length}")
}


{script
LAMBDATALK.DICT["W.unicodeLength"] = function() {
  function countCodePoints(str) {
    var point,
        index,
        width = 0,
        len = 0;
    for (index = 0; index < str.length;) {
      point = str.codePointAt(index);
      width = 0;
      while (point) {
          width += 1;
          point = point >> 8;
      }
      index += Math.round(width/2);
      len += 1;
    }
    return len;
  }
  var args = arguments[0].trim();
  return countCodePoints(args)
};
}

Testing:

{W.length Hello, World!} -> 13

{W.length José}          -> 4
{W.unicodeLength José}   -> 4

{W.length 𝔘𝔫𝔦𝔠𝔬𝔡𝔢}        -> 14
{W.unicodeLength 𝔘𝔫𝔦𝔠𝔬𝔡𝔢} -> 7


'Hello, world!'->size // 13
'møøse'->size // 5
'𝔘𝔫𝔦𝔠𝔬𝔡𝔢'->size // 7


(length "ASCII text")
10
(length "𝔘𝔫𝔦𝔠𝔬𝔡𝔢 𝔗𝔢𝒙𝔱")
12
> (set encoded (binary ("𝔘𝔫𝔦𝔠𝔬𝔡𝔢 𝔗𝔢𝒙𝔱" utf8)))
#B(240 157 148 152 240 157 148 171 240 157 ...)
> (length (unicode:characters_to_list encoded 'utf8))
12


utf8Str = "Hello world äöü"
put utf8Str.length
-- 15


print count "|Hello World|  ; 11
print count "møøse            ; 5
print char 248   ; ø - implies ISO-Latin character set


A$=format$("J\u0332o\u0332s\u0332e\u0301\u0332")
Print Len(A$) = 9  ' true Utf-16LE
Print Len.Disp(A$) = 4 \\ display length
Buffer Clear Mem as Byte*100
\\ Write at memory at offset 0 or address Mem(0)
Return Mem, 0:=A$
Print Eval$(Mem, 0, 18)
For i=0 to 17 step 2
      \\ print hex value and character
      Hex Eval(Mem, i as integer), ChrCode$(Eval(Mem, i as integer))
Next i
Document B$=A$
\\ encode to utf-8 with BOM (3 bytes 0xEF,0xBB,0xBF)
Save.Doc B$, "Checklen.doc", 2
Print Filelen("Checklen.doc")=17
\\ So length is 14 bytes + 3 the BOM


s: "the quick brown fox jumps over the lazy dog";
slength(s);
/* 43 */


:- module string_byte_length.
:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.

:- implementation.

:- import_module list, string.

main(!IO) :-
    Words = ["møøse", "𝔘𝔫𝔦𝔠𝔬𝔡𝔢", "J\x332\o\x332\s\x332\e\x301\\x332\"],
    io.write_list(Words, "", write_length, !IO).

:- pred write_length(string::in, io::di, io::uo) is det.

write_length(String, !IO):-
    NumBytes = count_utf8_code_units(String),
    io.format("%s: %d bytes\n", [s(String), i(NumBytes)], !IO).


string s;
s := "Hello Moose";
show length(s);          % 11 (ok)
s := "Hello Møøse";
show length(s);          % 13 (number of bytes when the string is UTF-8 encoded,
                         % since ø takes two bytes)


.data
	#.asciiz automatically adds the NULL terminator character, \0 for us.
	string: .asciiz "Nice string you got there!"

.text
main:
	la $a1,string           #load the beginning address of the string.

loop:
	lb $a2,($a1)            #load byte (i.e. the char) at $a1 into $a2
	addi $a1,$a1,1          #increment $a1
	beqz $a2,exit_procedure #see if we've hit the NULL char yet
	addi $a0,$a0,1          #increment counter
	j loop                  #back to start

exit_procedure:
	li $v0,1                #set syscall to print integer
	syscall

	li $v0,10               #set syscall to cleanly exit EXIT_SUCCESS
	syscall


alias stringlength { echo -a Your Name is: $len($$?="Whats your name") letters long! }


MODULE ByteLength EXPORTS Main;

IMPORT IO, Fmt, Text;

VAR s: TEXT := "Foo bar baz";

BEGIN
  IO.Put("Byte length of s: " & Fmt.Int((Text.Length(s) * BYTESIZE(s))) & "\n");
END ByteLength.


def message = "How long am I anyways?";
def charlength = message.Length;


(set 'Str "møøse")
(println  Str  " is " (length Str) " characters long")


import strformat, unicode

var s: string = "Hello, world! ☺"

echo &"“{s}” has byte length {s.len}."
echo &"“{s}” has Unicode char length {s.runeLen}."


MODULE Size;

   IMPORT Out;

   VAR s: LONGINT;
      string: ARRAY 5 OF CHAR;

BEGIN
   string := "Foo";
   s := LEN(string);
   Out.String("Size: ");
   Out.LongInt(s,0);
   Out.Ln;
END Size.


// Return the length in characters
// XXX: does not (always) count Unicode characters (code points)!
unsigned int numberOfCharacters = [@"møøse" length];  // 5


; Character length
(print (string-length "Hello, wørld!"))
; ==> 13

; Byte (utf-8 encoded) length
(print (length (string->bytes "Hello, wørld!")))
; ==> 14


DEF VAR lcc AS LONGCHAR.

FIX-CODEPAGE( lcc ) = "UTF-8".
lcc = "møøse".

MESSAGE LENGTH( lcc ) VIEW-AS ALERT-BOX.


len(s)=#s; \\ Alternately, len(s)=length(s); or even len=length;


const
  s = 'abcdef';
begin
  writeln (length(s))
end.


use utf8; # so we can use literal characters like ☺ in source
use Encode qw(encode);

print length encode 'UTF-8', "Hello, world! ☺";
# 17. The last character takes 3 bytes, the others 1 byte each.

print length encode 'UTF-16', "Hello, world! ☺";
# 32. 2 bytes for the BOM, then 15 byte pairs for each character.


constant s = "𝔘𝔫𝔦𝔠𝔬𝔡𝔢"
?length(s)
?length(utf8_to_utf32(s))


<?php
foreach (array('møøse', '𝔘𝔫𝔦𝔠𝔬𝔡𝔢', 'J̲o̲s̲é̲') as $s1) {
   printf('String "%s" measured with strlen: %d mb_strlen: %s grapheme_strlen %s%s',
                  $s1, strlen($s1),mb_strlen($s1), grapheme_strlen($s1), PHP_EOL);
}


(let Str "møøse"
   (prinl "Character Length of \"" Str "\" is " (length Str))
   (prinl "Byte Length of \"" Str "\" is " (size Str)) )


declare WS widechar (13) initial ('Hello world.');
put ('Character length=', length (WS));
put skip list ('Byte length=', size(WS));

declare SM graphic (13) initial ('Hello world');
put ('Character length=', length(SM));
put skip list ('Byte length=', size(trim(SM)));


DECLARE
  string VARCHAR2(50) := 'Hello, world!';
  stringlength NUMBER;
BEGIN
  stringlength := LENGTHB(string);
END;


lvars str = 'Hello, world!';
lvars len = length(str);


"møøse" length print
"𝔘𝔫𝔦𝔠𝔬𝔡𝔢" length print
"J̲o̲s̲é̲" length print


print(‘abcd’.starts_with(‘ab’))
print(‘abcd’.ends_with(‘zn’))
print(‘bb’ C ‘abab’)
print(‘ab’ C ‘abab’)
print(‘abab’.find(‘bb’) ? -1)
print(‘abab’.find(‘ab’) ? -1)


a <- "m\u00f8\u00f8se"
print(nchar(a, type="bytes"))  # print 7


*        String matching           04/04/2017
STRMATCH CSECT
         USING  STRMATCH,R15
         XPRNT  SS,L'SS
*
         CLC    SS(L'S1),S1
         BNE    NOT1
         XPRNT  =C'-- STARTS WITH',14
         XPRNT  S1,L'S1
NOT1     EQU    *
*
         CLC    SS+L'SS-L'S2(L'S2),S2
         BNE    NOT2
         XPRNT  =C'-- ENDS WITH',12
         XPRNT  S2,L'S2
NOT2     EQU    *
*
         LA     R0,L'SS-L'S3+1
         LA     R1,SS
LOOP     CLC    0(L'S3,R1),S3
         BNE    NOT3
         XPRNT  =C'-- CONTAINS',11
         XPRNT  S3,L'S3
NOT3     LA     R1,1(R1)
         BCT    R0,LOOP
*
         BR     R14
SS       DC     CL6'ABCDEF'
S1       DC     CL2'AB'
S2       DC     CL2'EF'
S3       DC     CL2'CD'
PG       DC     CL80' '
         YREGS
         END    STRMATCH


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program strMatching64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
/*******************************************/
/* Initialized data                        */
/*******************************************/
.data
szMessFound:             .asciz "String found. \n"
szMessNotFound:          .asciz "String not found. \n"
szString:                .asciz "abcdefghijklmnopqrstuvwxyz"
szString2:               .asciz "abc"
szStringStart:           .asciz "abcd"
szStringEnd:             .asciz "xyz"
szStringStart2:          .asciz "abcd"
szStringEnd2:            .asciz "xabc"
szCarriageReturn:        .asciz "\n"
/*******************************************/
/* UnInitialized data                      */
/*******************************************/
.bss
/*******************************************/
/*  code section                           */
/*******************************************/
.text
.global main
main:

    ldr x0,qAdrszString                  // address input string
    ldr x1,qAdrszStringStart             // address search string

    bl searchStringDeb                   // Determining if the first string starts with second string
    cmp x0,0
    ble 1f
    ldr x0,qAdrszMessFound               // display message
    bl affichageMess
    b 2f
1:
    ldr x0,qAdrszMessNotFound
    bl affichageMess
2:
    ldr x0,qAdrszString                 // address input string
    ldr x1,qAdrszStringEnd              // address search string
    bl searchStringFin                  // Determining if the first string ends with the second string
    cmp x0,0
    ble 3f
    ldr x0,qAdrszMessFound              // display message
    bl affichageMess
    b 4f
3:
    ldr x0,qAdrszMessNotFound
    bl affichageMess
4:
    ldr x0,qAdrszString2               // address input string
    ldr x1,qAdrszStringStart2          // address search string

    bl searchStringDeb                 //
    cmp x0,0
    ble 5f
    ldr x0,qAdrszMessFound             // display message
    bl affichageMess
    b 6f
5:
    ldr x0,qAdrszMessNotFound
    bl affichageMess
6:
    ldr x0,qAdrszString2               // address input string
    ldr x1,qAdrszStringEnd2            // address search string
    bl searchStringFin
    cmp x0,0
    ble 7f
    ldr x0,qAdrszMessFound            // display message
    bl affichageMess
    b 8f
7:
    ldr x0,qAdrszMessNotFound
    bl affichageMess
8:
    ldr x0,qAdrszString               // address input string
    ldr x1,qAdrszStringEnd            // address search string
    bl searchSubString                // Determining if the first string contains the second string at any location
    cmp x0,0
    ble 9f
    ldr x0,qAdrszMessFound            // display message
    bl affichageMess
    b 10f
9:
    ldr x0,qAdrszMessNotFound         // display substring result
    bl affichageMess
10:

100:                                  // standard end of the program
    mov x0,0                          // return code
    mov x8,EXIT                       // request to exit program
    svc 0                             // perform system call
qAdrszMessFound:          .quad szMessFound
qAdrszMessNotFound:       .quad szMessNotFound
qAdrszString:             .quad szString
qAdrszString2:            .quad szString2
qAdrszStringStart:        .quad szStringStart
qAdrszStringEnd:          .quad szStringEnd
qAdrszStringStart2:       .quad szStringStart2
qAdrszStringEnd2:         .quad szStringEnd2
qAdrszCarriageReturn:     .quad szCarriageReturn
/******************************************************************/
/*     search substring at begin of input string                  */
/******************************************************************/
/* x0 contains the address of the input string */
/* x1 contains the address of substring */
/* x0 returns 1 if find or 0 if not or -1 if error */
searchStringDeb:
    stp x1,lr,[sp,-16]!            // save  registers
    stp x2,x3,[sp,-16]!            // save  registers
    mov x3,0                       // counter byte  string
    ldrb w4,[x1,x3]                // load first byte of substring
    cbz x4,99f                     // empty string ?
1:
    ldrb w2,[x0,x3]                // load byte string input
    cbz x2,98f                     // zero final ?
    cmp x4,x2                      // bytes equals ?
    bne 98f                        // no not find
    add x3,x3,1                    // increment counter
    ldrb w4,[x1,x3]                // and load next byte of substring
    cbnz x4,1b                     // zero final ?
    mov x0,1                       // yes is ok
    b 100f
98:
    mov x0,0                       // not find
    b 100f
99:
    mov x0,-1                      // error
100:
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30

/******************************************************************/
/*     search substring at end of input string                    */
/******************************************************************/
/* x0 contains the address of the input string */
/* x1 contains the address of substring */
/* x0 returns 1 if find or 0 if not or -1 if error */
searchStringFin:
    stp x1,lr,[sp,-16]!            // save  registers
    stp x2,x3,[sp,-16]!            // save  registers
    stp x4,x5,[sp,-16]!            // save  registers
    mov x3,0                       // counter byte  string
                                   // search the last character of substring
1:
    ldrb w4,[x1,x3]                // load byte of substring
    cmp x4,#0                      // zero final ?
    add x2,x3,1
    csel x3,x2,x3,ne               // no increment counter
    //addne x3,#1                  // no increment counter
    bne 1b                         // and loop
    cbz x3,99f                     // empty string ?

    sub x3,x3,1                    // index of last byte
    ldrb w4,[x1,x3]                // load last byte of substring
                                   // search the last character of string
    mov x2,0                       // index last character
2:
    ldrb w5,[x0,x2]                // load first byte of substring
    cmp x5,0                       // zero final ?
    add x5,x2,1                    // no -> increment counter
    csel x2,x5,x2,ne
    //addne x2,#1                  // no -> increment counter
    bne 2b                         // and loop
    cbz x2,98f                     // empty input string ?
    sub x2,x2,1                    // index last character
3:
    ldrb w5,[x0,x2]                // load byte string input
    cmp x4,x5                      // bytes equals ?
    bne 98f                        // no -> not found
    subs x3,x3,1                   // decrement counter
    blt 97f                        //  ok found
    subs x2,x2,1                   // decrement counter input string
    blt 98f                        // if zero -> not found
    ldrb w4,[x1,x3]                // load previous byte of substring
    b 3b                           // and loop
97:
    mov x0,1                       // yes is ok
    b 100f
98:
    mov x0,0                       // not found
    b 100f
99:
    mov x0,-1                      // error
100:
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30

/******************************************************************/
/*   search a substring in the string                            */
/******************************************************************/
/* x0 contains the address of the input string */
/* x1 contains the address of substring */
/* x0 returns index of substring in string or -1 if not found */
searchSubString:
    stp x1,lr,[sp,-16]!            // save  registers
    stp x2,x3,[sp,-16]!            // save  registers
    stp x4,x5,[sp,-16]!            // save  registers
    mov x2,0                       // counter byte input string
    mov x3,0                       // counter byte string
    mov x6,-1                      // index found
    ldrb w4,[x1,x3]
1:
    ldrb w5,[x0,x2]                // load byte string
    cbz x5,99f                     // zero final ?
    cmp x5,x4                      // compare character
    beq 2f
    mov x6,-1                      // no equals - > raz index
    mov x3,0                       // and raz counter byte
    add x2,x2,1                    // and increment counter byte
    b 1b                           // and loop
2:                                 // characters equals
    cmp x6,-1                      // first characters equals ?
    csel x6,x2,x6,eq               // yes -> index begin in x6
    //moveq x6,x2                  // yes -> index begin in x6
    add x3,x3,1                    // increment counter substring
    ldrb w4,[x1,x3]                // and load next byte
    cmp x4,0                       // zero final ?
    beq 3f                         // yes -> end search
    add x2,x2,1                    // else increment counter string
    b 1b                           // and loop
3:
    mov x0,x6
    b 100f

98:
    mov x0,0                      // not found
    b 100f
99:
    mov x0,-1                     // error
100:
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


BYTE FUNC FindS(CHAR ARRAY text,sub BYTE start)
  BYTE i,j,found

  i=start
  WHILE i<=text(0)-sub(0)+1
  DO
    found=0
    FOR j=1 TO sub(0)
    DO
      IF text(i+j-1)#sub(j) THEN
        found=0 EXIT
      ELSE
        found=1
      FI
    OD
    IF found THEN
      RETURN (i)
    FI
    i==+1
  OD
RETURN (0)

BYTE FUNC StartsWith(CHAR ARRAY text,sub)
  BYTE pos

  pos=FindS(text,sub,1)
  IF pos=1 THEN
    RETURN (1)
  FI
RETURN (0)

BYTE FUNC EndsWith(CHAR ARRAY text,sub)
  BYTE pos,start

  IF sub(0)>text(0) THEN
    RETURN (0)
  FI
  start=text(0)-sub(0)+1
  pos=FindS(text,sub,start)
  IF pos=start THEN
    RETURN (1)
  FI
RETURN (0)

BYTE FUNC Contains(CHAR ARRAY text,sub
                  BYTE ARRAY positions)
  BYTE pos,count

  pos=1 count=0
  WHILE pos<=text(0)
  DO
    pos=FindS(text,sub,pos)
    IF pos>0 THEN
      positions(count)=pos
      count==+1
      pos==+1
    ELSE
      EXIT
    FI
  OD
RETURN (count)

PROC TestStartsWith(CHAR ARRAY text,sub)
  IF StartsWith(text,sub) THEN
    PrintF("""%S"" starts with ""%S"".%E",text,sub)
  ELSE
    PrintF("""%S"" does not start with ""%S"".%E",text,sub)
  FI
RETURN

PROC TestEndsWith(CHAR ARRAY text,sub)
  IF EndsWith(text,sub) THEN
    PrintF("""%S"" ends with ""%S"".%E",text,sub)
  ELSE
    PrintF("""%S"" does not end with ""%S"".%E",text,sub)
  FI
RETURN

PROC TestContains(CHAR ARRAY text,sub)
  BYTE ARRAY positions(20)
  BYTE i,count

  count=Contains(text,sub,positions)
  IF count>0 THEN
    PrintF("""%S"" contains %B ""%S"" at positions:",text,count,sub)
    FOR i=0 TO count-1
    DO
      PrintB(positions(i))
      IF i<count-1 THEN
        Print(", ")
      ELSE
        PrintE(".")
      FI
    OD
  ELSE
    PrintF("""%S"" does not contain ""%S"".%E",text,sub)
  FI
RETURN

PROC Main()
  TestStartsWith("1234abc","123")
  TestStartsWith("1234abc","234")
  PutE()
  TestContains("abbaabab","ab")
  TestContains("abbaabab","ba")
  TestContains("abbaabab","xyz")
  PutE()
  TestEndsWith("1234abc","abc")
  TestEndsWith("1234abc","ab")
RETURN


;; r2
length? "møøse"

;; r3
length? to-binary "møøse"


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

procedure Match_Strings is
   S1 : constant String := "abcd";
   S2 : constant String := "abab";
   S3 : constant String := "ab";
begin
   if S1'Length >= S3'Length and then S1 (S1'First..S1'First + S3'Length - 1) = S3 then
      Put_Line (''' & S1 & "' starts with '" & S3 & ''');
   end if;
   if S2'Length >= S3'Length and then S2 (S2'Last - S3'Length + 1..S2'Last) = S3 then
      Put_Line (''' & S2 & "' ends with '" & S3 & ''');
   end if;
   Put_Line (''' & S3 & "' first appears in '" & S1 & "' at" & Integer'Image (Index (S1, S3)));
   Put_Line
   (  ''' & S3 & "' appears in '" & S2 & ''' &
      Integer'Image (Ada.Strings.Fixed.Count (S2, S3)) & " times"
   );
end Match_Strings;


text t;
data b;

b = "Bangkok";

t = "Bang";

o_form("starts with, embeds, ends with \"~\": ~, ~, ~\n", t, b.seek(t) == 0,
       b.seek(t) != -1,
       b.seek(t) != -1 && b.seek(t) + ~t == ~b);

t = "ok";

o_form("starts with, embeds, ends with \"~\": ~, ~, ~\n", t, b.seek(t) == 0,
       b.seek(t) != -1,
       b.seek(t) != -1 && b.seek(t) + ~t == ~b);

t = "Summer";

o_form("starts with, embeds, ends with \"~\": ~, ~, ~\n", t, b.seek(t) == 0,
       b.seek(t) != -1,
       b.seek(t) != -1 && b.seek(t) + ~t == ~b);


/*REXX program displays the lengths  (in bytes/characters)  for various strings.        */
    /*            1         */                         /*a handy-dandy over/under scale.*/
    /*   123456789012345    */
hello = 'Hello, world!'      ;        say  'the length of HELLO is '   length(hello)
happy = 'Hello, world! ☺'    ;        say  'the length of HAPPY is '   length(happy)
jose  = 'José'               ;        say  'the length of  JOSE is '   length(jose)
nill  = ''                   ;        say  'the length of  NILL is '   length(nill)
null  =                      ;        say  'the length of  NULL is '   length(null)
sum   = 5+1                  ;        say  'the length of   SUM is '   length(sum)
                                                       /*   [↑]  is, of course,  6.     */
                                                       /*stick a fork in it, we're done.*/


aString = "Welcome to the Ring Programming Language"
aStringSize = len(aString)
see  "Character lenghts : " + aStringSize


set "$local1" to "Hello world!"
* "String length: &$local1.length&"
end


# define some appropriate OPerators #
PRIO STARTSWITH = 5, ENDSWITH = 5;
OP STARTSWITH = (STRING str, prefix)BOOL: # assuming LWB = 1 #
  IF UPB str < UPB prefix THEN FALSE ELSE str[:UPB prefix]=prefix FI;
OP ENDSWITH = (STRING str, suffix)BOOL: # assuming LWB = 1 #
  IF UPB str < UPB suffix THEN FALSE ELSE str[UPB str-UPB suffix+1:]=suffix FI;

INT loc, loc2;

print((
  "abcd" STARTSWITH "ab", # returns TRUE #
  "abcd" ENDSWITH "zn", # returns FALSE #
  string in string("bb",loc,"abab"), # returns FALSE #
  string in string("ab",loc,"abab"), # returns TRUE #
  (string in string("bb",loc,"abab")|loc|-1), # returns -1 #
  (string in string("ab",loc,"abab")|loc|-1), # returns +1 #
  (string in string("ab",loc2,"abab"[loc+1:])|loc+loc2|-1) # returns +3 #
))


set stringA to "I felt happy because I saw the others were happy and because I knew I should feel happy, but I wasn’t really happy."

set string1 to "I felt happy"
set string2 to "I should feel happy"
set string3 to "I wasn't really happy"

-- Determining if the first string starts with second string
stringA starts with string1  --> true

-- Determining if the first string contains the second string at any location
stringA contains string2     --> true

-- Determining if the first string ends with the second string
stringA ends with string3    --> false

-- Print the location of the match for part 2
offset of string2 in stringA --> 69


fn main() {
    let s = "文字化け";  // UTF-8
    println!("Byte Length: {}", s.len());
}


data _null_;
   a="Hello, World!";
   b=length(c);
   put _all_;
run;


/* ARM assembly Raspberry PI  */
/*  program strMatching.s   */

/* Constantes    */
.equ STDOUT, 1                           @ Linux output console
.equ EXIT,   1                           @ Linux syscall
.equ WRITE,  4                           @ Linux syscall

/* Initialized data */
.data
szMessFound:             .asciz "String found. \n"
szMessNotFound:          .asciz "String not found. \n"
szString:                .asciz "abcdefghijklmnopqrstuvwxyz"
szString2:               .asciz "abc"
szStringStart:           .asciz "abcd"
szStringEnd:             .asciz "xyz"
szStringStart2:          .asciz "abcd"
szStringEnd2:            .asciz "xabc"
szCarriageReturn:        .asciz "\n"

/* UnInitialized data */
.bss

/*  code section */
.text
.global main
main:

    ldr r0,iAdrszString                         @ address input string
    ldr r1,iAdrszStringStart                    @ address search string

    bl searchStringDeb                          @ Determining if the first string starts with second string
    cmp r0,#0
    ble 1f
    ldr r0,iAdrszMessFound                      @ display message
    bl affichageMess
    b 2f
1:
    ldr r0,iAdrszMessNotFound
    bl affichageMess
2:
    ldr r0,iAdrszString                         @ address input string
    ldr r1,iAdrszStringEnd                      @ address search string
    bl searchStringFin                          @ Determining if the first string ends with the second string
    cmp r0,#0
    ble 3f
    ldr r0,iAdrszMessFound                      @ display message
    bl affichageMess
    b 4f
3:
    ldr r0,iAdrszMessNotFound
    bl affichageMess
4:
    ldr r0,iAdrszString2                        @ address input string
    ldr r1,iAdrszStringStart2                   @ address search string

    bl searchStringDeb                          @
    cmp r0,#0
    ble 5f
    ldr r0,iAdrszMessFound                      @ display message
    bl affichageMess
    b 6f
5:
    ldr r0,iAdrszMessNotFound
    bl affichageMess
6:
    ldr r0,iAdrszString2                        @ address input string
    ldr r1,iAdrszStringEnd2                     @ address search string
    bl searchStringFin
    cmp r0,#0
    ble 7f
    ldr r0,iAdrszMessFound                      @ display message
    bl affichageMess
    b 8f
7:
    ldr r0,iAdrszMessNotFound
    bl affichageMess
8:
    ldr r0,iAdrszString                         @ address input string
    ldr r1,iAdrszStringEnd                      @ address search string
    bl searchSubString                          @ Determining if the first string contains the second string at any location
    cmp r0,#0
    ble 9f
    ldr r0,iAdrszMessFound                      @ display message
    bl affichageMess
    b 10f
9:
    ldr r0,iAdrszMessNotFound                   @ display substring result
    bl affichageMess
10:

100:                                            @ standard end of the program
    mov r0, #0                                  @ return code
    mov r7, #EXIT                               @ request to exit program
    svc 0                                       @ perform system call
iAdrszMessFound:          .int szMessFound
iAdrszMessNotFound:       .int szMessNotFound
iAdrszString:             .int szString
iAdrszString2:            .int szString2
iAdrszStringStart:        .int szStringStart
iAdrszStringEnd:          .int szStringEnd
iAdrszStringStart2:       .int szStringStart2
iAdrszStringEnd2:         .int szStringEnd2
iAdrszCarriageReturn:     .int szCarriageReturn
/******************************************************************/
/*     search substring at begin of input string                  */
/******************************************************************/
/* r0 contains the address of the input string */
/* r1 contains the address of substring */
/* r0 returns 1 if find or 0 if not or -1 if error */
searchStringDeb:
    push {r1-r4,lr}                             @ save  registers
    mov r3,#0                                   @ counter byte  string
    ldrb r4,[r1,r3]                             @ load first byte of substring
    cmp r4,#0                                   @ empty string ?
    moveq r0,#-1                                @ error
    beq 100f
1:
    ldrb r2,[r0,r3]                             @ load byte string input
    cmp r2,#0                                   @ zero final ?
    moveq r0,#0                                 @ not find
    beq 100f
    cmp r4,r2                                   @ bytes equals ?
    movne r0,#0                                 @ no not find
    bne 100f
    add r3,#1                                   @ increment counter
    ldrb r4,[r1,r3]                             @ and load next byte of substring
    cmp r4,#0                                   @ zero final ?
    bne 1b                                      @ no -> loop
    mov r0,#1                                   @ yes is ok
100:
    pop {r1-r4,lr}                              @ restaur registers
    bx lr                                       @ return

/******************************************************************/
/*     search substring at end of input string                    */
/******************************************************************/
/* r0 contains the address of the input string */
/* r1 contains the address of substring */
/* r0 returns 1 if find or 0 if not or -1 if error */
searchStringFin:
    push {r1-r5,lr}                             @ save  registers
    mov r3,#0                                   @ counter byte  string
                                                @ search the last character of substring
1:
    ldrb r4,[r1,r3]                             @ load byte of substring
    cmp r4,#0                                   @ zero final ?
    addne r3,#1                                 @ no increment counter
    bne 1b                                      @ and loop
    cmp r3,#0                                   @ empty string ?
    moveq r0,#-1                                @ error
    beq 100f
    sub r3,#1                                   @ index of last byte
    ldrb r4,[r1,r3]                             @ load last byte of substring
                                                @ search the last character of string
    mov r2,#0                                   @ index last character
2:
    ldrb r5,[r0,r2]                             @ load first byte of substring
    cmp r5,#0                                   @ zero final ?
    addne r2,#1                                 @ no -> increment counter
    bne 2b                                      @ and loop
    cmp r2,#0                                   @ empty input string ?
    moveq r0,#0                                 @ yes -> not found
    beq 100f
    sub r2,#1                                   @ index last character
3:
    ldrb r5,[r0,r2]                             @ load byte string input
    cmp r4,r5                                   @ bytes equals ?
    movne r0,#0                                 @ no -> not found
    bne 100f
    subs r3,#1                                  @ decrement counter
    movlt r0,#1                                 @ if zero -> ok found
    blt 100f
    subs r2,#1                                  @ decrement counter input string
    movlt r0,#0                                 @ if zero -> not found
    blt 100f
    ldrb r4,[r1,r3]                             @ load previous byte of substring
    b 3b                                        @ and loop

100:
    pop {r1-r5,lr}                              @ restaur registers
    bx lr                                       @ return

/******************************************************************/
/*   search a substring in the string                            */
/******************************************************************/
/* r0 contains the address of the input string */
/* r1 contains the address of substring */
/* r0 returns index of substring in string or -1 if not found */
searchSubString:
    push {r1-r6,lr}                       @ save registers
    mov r2,#0                             @ counter byte input string
    mov r3,#0                             @ counter byte string
    mov r6,#-1                            @ index found
    ldrb r4,[r1,r3]
1:
    ldrb r5,[r0,r2]                       @ load byte string
    cmp r5,#0                             @ zero final ?
    moveq r0,#-1                          @ yes returns error
    beq 100f
    cmp r5,r4                             @ compare character
    beq 2f
    mov r6,#-1                            @ no equals - > raz index
    mov r3,#0                             @ and raz counter byte
    add r2,#1                             @ and increment counter byte
    b 1b                                  @ and loop
2:                                        @ characters equals
    cmp r6,#-1                            @ first characters equals ?
    moveq r6,r2                           @ yes -> index begin in r6
    add r3,#1                             @ increment counter substring
    ldrb r4,[r1,r3]                       @ and load next byte
    cmp r4,#0                             @ zero final ?
    beq 3f                                @ yes -> end search
    add r2,#1                             @ else increment counter string
    b 1b                                  @ and loop
3:
    mov r0,r6
100:
    pop {r1-r6,lr}                        @ restaur registers
    bx lr

/******************************************************************/
/*     display text with size calculation                         */
/******************************************************************/
/* r0 contains the address of the message */
affichageMess:
    push {r0,r1,r2,r7,lr}                       @ save  registers
    mov r2,#0                                   @ counter length */
1:                                              @ loop length calculation
    ldrb r1,[r0,r2]                             @ read octet start position + index
    cmp r1,#0                                   @ if 0 its over
    addne r2,r2,#1                              @ else add 1 in the length
    bne 1b                                      @ and loop
                                                @ so here r2 contains the length of the message
    mov r1,r0                                   @ address message in r1
    mov r0,#STDOUT                              @ code to write to the standard output Linux
    mov r7, #WRITE                              @ code call system "write"
    svc #0                                      @ call system
    pop {r0,r1,r2,r7,lr}                        @ restaur registers
    bx lr                                       @ return


object StringLength extends App {
  val s1 = "møøse"
  val s3 = List("\uD835\uDD18", "\uD835\uDD2B", "\uD835\uDD26",
    "\uD835\uDD20", "\uD835\uDD2C", "\uD835\uDD21", "\uD835\uDD22").mkString
  val s4 = "J\u0332o\u0332s\u0332e\u0301\u0332"

    List(s1, s3, s4).foreach(s => println(
        s"The string: $s, characterlength= ${s.length} UTF8bytes= ${
      s.getBytes("UTF-8").size
    } UTF16bytes= ${s.getBytes("UTF-16LE").size}"))
}


print prefix? "abcd" "ab"
print prefix? "abcd" "cd"
print suffix? "abcd" "ab"
print suffix? "abcd" "cd"

print contains? "abcd" "ab"
print contains? "abcd" "xy"

print in? "ab" "abcd"
print in? "xy" "abcd"

print index "abcd" "bc"
print index "abcd" "xy"


String1 = abcd
String2 = abab

If (SubStr(String1,1,StrLen(String2)) = String2)
 MsgBox, "%String1%" starts with "%String2%".
IfInString, String1, %String2%
{
 Position := InStr(String1,String2)
 StringReplace, String1, String1, %String2%, %String2%, UseErrorLevel
 MsgBox, "%String1%" contains "%String2%" at position %Position%`, and appears %ErrorLevel% times.
}
StringRight, TempVar, String1, StrLen(String2)
If TempVar = %String2%
 MsgBox, "%String1%" ends with "%String2%".


print(# "Hello, world!"); -- '#' is the cardinality operator. Works on strings, tuples, and sets.


møøse
𝔘𝔫𝔦𝔠𝔬𝔡𝔢
J̲o̲s̲é̲
€


$string1 = "arduinoardblobard"
$string2 = "ard"

; == Determining if the first string starts with second string
If StringLeft($string1, StringLen($string2)) = $string2 Then
	ConsoleWrite("1st string starts with 2nd string." & @CRLF)
Else
	ConsoleWrite("1st string does'nt starts with 2nd string." & @CRLF)
EndIf

; == Determining if the first string contains the second string at any location
; == Print the location of the match for part 2
; == Handle multiple occurrences of a string for part 2
$start = 1
$count = 0
$pos = StringInStr($string1, $string2)
While $pos
	$count += 1
	ConsoleWrite("1st string contains 2nd string at position: " & $pos & @CRLF)
	$pos = StringInStr($string1, $string2, 0, 1, $start + $pos + StringLen($string2))
WEnd
If $count = 0 Then ConsoleWrite("1st string does'nt contain 2nd string." & @CRLF)

; == Determining if the first string ends with the second string
If StringRight($string1, StringLen($string2)) = $string2 Then
	ConsoleWrite("1st string ends with 2nd string." & @CRLF)
Else
	ConsoleWrite("1st string does'nt ends with 2nd string." & @CRLF)
EndIf


	output = "Byte length: " size(trim(input))
end


#!/usr/bin/awk -f
{
    if ($1 ~ "^"$2) {
	print $1" begins with "$2;
    } else {
	print $1" does not begin with "$2;
    }

    if ($1 ~ $2) {
	print $1" contains "$2;
    } else {
	print $1" does not contain "$2;
    }

    if ($1 ~ $2"$") {
	print $1" ends with "$2;
    } else {
	print $1" does not end with "$2;
    }
}


first$ = "qwertyuiop"

'Determining if the first string starts with second string
second$ = "qwerty"
IF LEFT$(first$, LEN(second$)) = second$ THEN
    PRINT "'"; first$; "' starts with '"; second$; "'"
ELSE
    PRINT "'"; first$; "' does not start with '"; second$; "'"
END IF

'Determining if the first string contains the second string at any location
'Print the location of the match for part 2
second$ = "wert"
x = INSTR(first$, second$)
IF x THEN
    PRINT "'"; first$; "' contains '"; second$; "' at position "; x
ELSE
    PRINT "'"; first$; "' does not contain '"; second$; "'"
END IF

' Determining if the first string ends with the second string
second$ = "random garbage"
IF RIGHT$(first$, LEN(second$)) = second$ THEN
    PRINT "'"; first$; "' ends with '"; second$; "'"
ELSE
    PRINT "'"; first$; "' does not end with '"; second$; "'"
END IF


VALUES LENGTH('møøse', CODEUNITS16);
VALUES LENGTH('møøse', CODEUNITS32);
VALUES CHARACTER_LENGTH('møøse', CODEUNITS32);
VALUES LENGTH2('møøse');
VALUES LENGTH4('møøse');
VALUES LENGTH('𝔘𝔫𝔦𝔠𝔬𝔡𝔢', CODEUNITS16);
VALUES LENGTH('𝔘𝔫𝔦𝔠𝔬𝔡𝔢', CODEUNITS32);
VALUES CHARACTER_LENGTH('𝔘𝔫𝔦𝔠𝔬𝔡𝔢', CODEUNITS32);
VALUES LENGTH2('𝔘𝔫𝔦𝔠𝔬𝔡𝔢');
VALUES LENGTH4('𝔘𝔫𝔦𝔠𝔬𝔡𝔢');
VALUES LENGTH('J̲o̲s̲é̲', CODEUNITS16);
VALUES LENGTH('J̲o̲s̲é̲', CODEUNITS32);
VALUES CHARACTER_LENGTH('J̲o̲s̲é̲', CODEUNITS32);
VALUES LENGTH2('J̲o̲s̲é̲');
VALUES LENGTH4('J̲o̲s̲é̲');


::NOTE #1: This implementation might crash, or might not work properly if
::you put some of the CMD special characters (ex. %,!, etc) inside the strings.
::
::NOTE #2: The comparisons here are case-SENSITIVE.
::NOTE #3: Spaces in strings are considered.

@echo off
setlocal enabledelayedexpansion

::The main things...
set "str1=qwertyuiop"
set "str2=qwerty"
call :str2_lngth
call :matchbegin

set "str1=qweiuoiocghiioyiocxiisfguiioiuygvd"
set "str2=io"
call :str2_lngth
call :matchcontain

set "str1=blablabla"
set "str2=bbla"
call :str2_lngth
call :matchend

echo.
pause
exit /b 0
::/The main things.

::The functions...
:matchbegin
echo.
if "!str1:~0,%length%!"=="!str2!" (
	echo "%str1%" begins with "%str2%".
) else (
	echo "%str1%" does not begin with "%str2%".
)
goto :EOF

:matchcontain
echo.
set curr=0&set exist=0
:scanchrloop
if "!str1:~%curr%,%length%!"=="" (
	if !exist!==0 echo "%str1%" does not contain "%str2%".
	goto :EOF
)
if "!str1:~%curr%,%length%!"=="!str2!" (
	echo "%str1%" contains "%str2%". ^(in Position %curr%^)
	set exist=1
)
set /a curr+=1&goto scanchrloop

:matchend
echo.
if "!str1:~-%length%!"=="!str2!" (
	echo "%str1%" ends with "%str2%".
) else (
	echo "%str1%" does not end with "%str2%".
)
goto :EOF

:str2_lngth
set length=0
:loop
if "!str2:~%length%,1!"=="" goto :EOF
set /a length+=1
goto loop
::/The functions.


scalar s="Ἐν ἀρχῇ ἐποίησεν ὁ θεὸς τὸν οὐρανὸν καὶ τὴν γῆν"

di strlen(s)
97

di ustrlen(s)
47


      first$ = "The fox jumps over the dog"

      FOR test% = 1 TO 3
        READ second$
        starts% = FN_first_starts_with_second(first$, second$)
        IF starts% PRINT """" first$ """ starts with """ second$ """"
        ends% = FN_first_ends_with_second(first$, second$)
        IF ends% PRINT """" first$ """ ends with """ second$ """"
        where% = FN_first_contains_second_where(first$, second$)
        IF where% PRINT """" first$ """ contains """ second$ """ at position " ; where%
        howmany% = FN_first_contains_second_howmany(first$, second$)
        IF howmany% PRINT """" first$ """ contains """ second$ """ " ; howmany% " time(s)"
      NEXT
      DATA "The", "he", "dog"
      END

      DEF FN_first_starts_with_second(A$, B$)
      = B$ = LEFT$(A$, LEN(B$))

      DEF FN_first_ends_with_second(A$, B$)
      = B$ = RIGHT$(A$, LEN(B$))

      DEF FN_first_contains_second_where(A$, B$)
      = INSTR(A$, B$)

      DEF FN_first_contains_second_howmany(A$, B$)
      LOCAL I%, N% : I% = 0
      REPEAT
        I% = INSTR(A$, B$, I%+1)
        IF I% THEN N% += 1
      UNTIL I% = 0
      = N%


SW ← ⊑⍷˜

Contains ← ∨´⍷˜

EW ← ¯1⊑⍷˜

Locs ← /⍷˜


let numberOfCharacters = "møøse".characters.count  // 5


string length [encoding convertto utf-8 $theString]


( (sentence="I want a number such that that number will be even.")
& out$(@(!sentence:I ?) & "sentence starts with 'I'" | "sentence does not start with 'I'")
& out$(@(!sentence:? such ?) & "sentence contains 'such'" | "sentence does not contain 'such'")
& out$(@(!sentence:? "even.") & "sentence ends with 'even.'" | "sentence does not end with 'even.'")
& 0:?N
& ( @(!sentence:? be (? & !N+1:?N & ~))
  | out$str$("sentence contains " !N " occurrences of 'be'")
  )
)


#include <string.h>
#include <stdio.h>

int startsWith(const char* container, const char* target)
{
  size_t clen = strlen(container), tlen = strlen(target);
  if (clen < tlen)
    return 0;
  return strncmp(container, target, tlen) == 0;
}

int endsWith(const char* container, const char* target)
{
  size_t clen = strlen(container), tlen = strlen(target);
  if (clen < tlen)
    return 0;
  return strncmp(container + clen - tlen, target, tlen) == 0;
}

int doesContain(const char* container, const char* target)
{
  return strstr(container, target) != 0;
}

int main(void)
{
  printf("Starts with Test ( Hello,Hell ) : %d\n", startsWith("Hello","Hell"));
  printf("Ends with Test ( Code,ode ) : %d\n", endsWith("Code","ode"));
  printf("Contains Test ( Google,msn ) : %d\n", doesContain("Google","msn"));

  return 0;
}


$$ MODE TUSCRIPT
string="hello, world"
l=LENGTH (string)
PRINT "character length of string '",string,"': ",l


string='Hello, world!'
length=`expr "x$string" : '.*' - 1`
echo $length # if you want it printed to the terminal


string s = "Hello, world!";
int characterLength = s.length;


class Program
{
	public static void Main (string[] args)
	{
		var value = "abcd".StartsWith("ab");
		value = "abcd".EndsWith("zn"); //returns false
		value = "abab".Contains("bb"); //returns false
		value = "abab".Contains("ab"); //returns true
		int loc = "abab".IndexOf("bb"); //returns -1
		loc = "abab".IndexOf("ab"); //returns 0
		loc = "abab".IndexOf("ab",loc+1); //returns 2
	}
}


#include <string>
using namespace std;

string s1="abcd";
string s2="abab";
string s3="ab";
//Beginning
s1.compare(0,s3.size(),s3)==0;
//End
s1.compare(s1.size()-s3.size(),s3.size(),s3)==0;
//Anywhere
s1.find(s2)//returns string::npos
int loc=s2.find(s3)//returns 0
loc=s2.find(s3,loc+1)//returns 2


Module ByteLength
    Function GetByteLength(s As String, encoding As Text.Encoding) As Integer
        Return encoding.GetByteCount(s)
    End Function
End Module


(def evals '((. "abcd" startsWith "ab")
	     (. "abcd" endsWith "zn")
	     (. "abab" contains "bb")
	     (. "abab" contains "ab")
	     (. "abab" indexOf "bb")
	     (let [loc (. "abab" indexOf "ab")]
	       (. "abab" indexOf "ab" (dec loc)))))

user> (for [i evals] [i (eval i)])
([(. "abcd" startsWith "ab") true] [(. "abcd" endsWith "zn") false] [(. "abab" contains "bb") false] [(. "abab" contains "ab") true] [(. "abab" indexOf "bb") -1] [(let [loc (. "abab" indexOf "ab")] (. "abab" indexOf "ab" (dec loc))) 0])


matchAt = (s, frag, i) ->
  s[i...i+frag.length] == frag

startsWith = (s, frag) ->
  matchAt s, frag, 0

endsWith = (s, frag) ->
  matchAt s, frag, s.length - frag.length

matchLocations = (s, frag) ->
  (i for i in [0..s.length - frag.length] when matchAt s, frag, i)

console.log startsWith "tacoloco", "taco" # true
console.log startsWith "taco", "tacoloco" # false
console.log startsWith "tacoloco", "talk" # false
console.log endsWith "tacoloco", "loco" # true
console.log endsWith "loco", "tacoloco" # false
console.log endsWith "tacoloco", "yoco" # false
console.log matchLocations "bababab", "bab" # [0,2,4]
console.log matchLocations "xxx", "x" # [0,1,2]


fn main() {
    m := "møøse"
    u := "𝔘𝔫𝔦𝔠𝔬𝔡𝔢"
    j := "J̲o̲s̲é̲"
    println("$m.len $m ${m.bytes()}")
    println("$u.len $u ${u.bytes()}")
    println("$j.len $j ${j.bytes()}")
}


.data
string:         .asciz "Test"

.text
.globl  main

main:
        pushl   %ebp
        movl    %esp, %ebp

        pushl   %edi
        xorb    %al, %al
        movl    $-1, %ecx
        movl    $string, %edi
        cld
        repne   scasb
        not     %ecx
        dec     %ecx
        popl    %edi

        ;; string length is stored in %ecx register

        leave
        ret


include c:\cxpl\stdlib;
IntOut(0, StrLen("Character length = Byte length = String length = "))


(defun starts-with-p (str1 str2)
  "Determine whether `str1` starts with `str2`"
  (let ((p (search str2 str1)))
    (and p (= 0 p))))

(print (starts-with-p "foobar" "foo")) ; T
(print (starts-with-p "foobar" "bar")) ; NIL

(defun ends-with-p (str1 str2)
  "Determine whether `str1` ends with `str2`"
  (let ((p (mismatch str2 str1 :from-end T)))
    (or (not p) (= 0 p))))

(print (ends-with-p "foobar" "foo")) ; NIL
(print (ends-with-p "foobar" "bar")) ; T

(defun containsp (str1 str2)
  "Determine whether `str1` contains `str2`.
   Instead of just returning T, return a list of starting locations
   for every occurence of `str2` in `str1`"
   (unless (string-equal str2 "")
     (loop for p = (search str2 str1) then (search str2 str1 :start2 (1+ p))
           while p
           collect p)))

(print (containsp "foobar" "oba")) ; (2)
(print (containsp "ababaBa" "ba")) ; (1 3)
(print (containsp "foobar" "x"))   ; NIL


MODULE StringMatch;
IMPORT StdLog,Strings;
CONST
	strSize = 1024;
	patSize = 256;

TYPE
	Matcher* = POINTER TO LIMITED RECORD
		str: ARRAY strSize OF CHAR;
		pat: ARRAY patSize OF CHAR;
		pos: INTEGER
	END;

PROCEDURE NewMatcher*(IN str: ARRAY OF CHAR): Matcher;
VAR
	m: Matcher;
BEGIN
	NEW(m);m.str := str$;m.pos:= 0;
	RETURN m
END NewMatcher;

PROCEDURE (m: Matcher) Match*(IN pat: ARRAY OF CHAR): INTEGER,NEW;
VAR
	pos: INTEGER;
BEGIN
	m.pat := pat$;
	pos := m.pos;
	Strings.Find(m.str,m.pat,pos,m.pos);
	RETURN m.pos
END Match;

PROCEDURE (m: Matcher) Next*(): INTEGER, NEW;
VAR
	pos: INTEGER;
BEGIN
	pos := m.pos + LEN(m.pat$);
	Strings.Find(m.str,m.pat,pos,m.pos);
	RETURN m.pos;
END Next;

(* Some Helper functions based on Strings module *)
PROCEDURE StartsWith(IN str: ARRAY OF CHAR;IN pat: ARRAY OF CHAR): BOOLEAN;
VAR
	pos: INTEGER;
BEGIN
	Strings.Find(str,pat,0,pos);
	RETURN pos = 0
END StartsWith;

PROCEDURE Contains(IN str: ARRAY OF CHAR;IN pat: ARRAY OF CHAR; OUT pos: INTEGER): BOOLEAN;
BEGIN
	Strings.Find(str,pat,0,pos);
	RETURN pos >= 0
END Contains;

PROCEDURE EndsWith(IN str: ARRAY OF CHAR;IN pat: ARRAY OF CHAR): BOOLEAN;
VAR
	pos: INTEGER;
BEGIN
	Strings.Find(str,pat,0,pos);
	RETURN pos + LEN(pat$) = LEN(str$)
END EndsWith;

PROCEDURE Do*;
CONST
	aStr = "abcdefghijklmnopqrstuvwxyz";
VAR
	pat: ARRAY 128 OF CHAR;
	res: BOOLEAN;
	at: INTEGER;
	m: Matcher;
BEGIN
	(* StartsWith *)
	pat := "abc";
	StdLog.String(aStr + " startsWith " + pat + " :>");StdLog.Bool(StartsWith(aStr,pat));StdLog.Ln;
	pat := "cba";
	StdLog.String(aStr + " startsWith " + pat + " :>");StdLog.Bool(StartsWith(aStr,pat));StdLog.Ln;
	pat := "def";
	StdLog.String(aStr + " startsWith " + pat + " :>");StdLog.Bool(StartsWith(aStr,pat));StdLog.Ln;
	StdLog.Ln;
	(* Contains *)
	pat := 'def';
	StdLog.String(aStr + " contains " + pat + " :>");StdLog.Bool(Contains(aStr,pat,at));
	StdLog.String(" at: ");StdLog.Int(at);StdLog.Ln;
	pat := 'efd';
	StdLog.String(aStr + " contains " + pat + " :>");StdLog.Bool(Contains(aStr,pat,at));
	StdLog.String(" at: ");StdLog.Int(at);StdLog.Ln;
	pat := 'abc';
	StdLog.String(aStr + " contains " + pat + " :>");StdLog.Bool(Contains(aStr,pat,at));
	StdLog.String(" at: ");StdLog.Int(at);StdLog.Ln;
	pat := 'xyz';
	StdLog.String(aStr + " contains " + pat + " :>");StdLog.Bool(Contains(aStr,pat,at));
	StdLog.String(" at: ");StdLog.Int(at);StdLog.Ln;
	StdLog.Ln;
	(* EndsWith *)
	pat := 'xyz';
	StdLog.String(aStr + " endsWith " + pat + " :>");StdLog.Bool(EndsWith(aStr,pat));StdLog.Ln;
	pat := 'zyx';
	StdLog.String(aStr + " endsWith " + pat + " :>");StdLog.Bool(EndsWith(aStr,pat));StdLog.Ln;
	pat := 'abc';
	StdLog.String(aStr + " endsWith " + pat + " :>");StdLog.Bool(EndsWith(aStr,pat));StdLog.Ln;
	pat:= 'def';
	StdLog.String(aStr + " endsWith " + pat + " :>");StdLog.Bool(EndsWith(aStr,pat));StdLog.Ln;
	StdLog.Ln;

	m := NewMatcher("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
	StdLog.String("Matching 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' against 'abc':> ");
	StdLog.Ln;
	StdLog.String("Match at: ");StdLog.Int(m.Match("abc"));StdLog.Ln;
	StdLog.String("Match at: ");StdLog.Int(m.Next());StdLog.Ln;
	StdLog.String("Match at: ");StdLog.Int(m.Next());StdLog.Ln
END Do;
END StringMatch.


; input: HL - pointer to the 0th char of a string.
; outputs length to B. HL will point to the last character in the string just before the terminator.
; length is one-indexed and does not include the terminator. A null string will return 0 in B.

; "Terminator" is a label for a constant that can be configured in the source code. My code uses 0.
; Sample Usage:
;      ld hl,MyString
;      call GetStringLength

GetStringLength:
		ld b,0
loop_getStringLength:
		ld a,(hl)      ;load the next char
		cp Terminator  ;is it the terminator?
		ret z          ;if so, exit.
		inc hl         ;next char
		inc b          ;increment the byte count
		jr loop_getStringLength