String matching: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Bracmat example)
Line 167: Line 167:
"The fox jumps over the dog" contains "dog" at position 24
"The fox jumps over the dog" contains "dog" at position 24
"The fox jumps over the dog" contains "dog" 1 time(s)</pre>
"The fox jumps over the dog" contains "dog" 1 time(s)</pre>

=={{header|Bracmat}}==
Bracmat does pattern matching in expressions <code><i>subject</i>:<i>pattern</i></code> and in strings <code>@(<i>subject</i>:<i>pattern</i>)</code>. The (sub)pattern <code>?</code> is a wild card.
<lang>( (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'")
)
)</lang>
In the last line, Bracmat is forced by the always failing node <code>~</code> to backtrack until all occurrences of 'be' are found. Thereafter the pattern match expression fails. The interesting part is the side effect: while backtracking, the accumulator <code>N</code> keeps track of how many are found.

Output:
<lang>sentence starts with 'I'
sentence contains 'such'
sentence ends with 'even.'
sentence contains 3 occurrences of 'be'</lang>


=={{header|C}}==
=={{header|C}}==

Revision as of 17:09, 5 February 2012

Task
String matching
You are encouraged to solve this task according to the task description, using any language you may know.

Basic Data Operation
This is a basic data operation. It represents a fundamental action on a basic data type.

You may see other such operations in the Basic Data Operations category, or:

Integer Operations
Arithmetic | Comparison

Boolean Operations
Bitwise | Logical

String Operations
Concatenation | Interpolation | Comparison | Matching

Memory Operations
Pointers & references | Addresses

Given two strings, demonstrate the following 3 types of matchings:

  1. Determining if the first string starts with second string
  2. Determining if the first string contains the second string at any location
  3. Determining if the first string ends with the second string

Optional requirements:

  1. Print the location of the match for part 2
  2. Handle multiple occurrences of a string for part 2.

Ada

<lang Ada> 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; </lang> Sample output:

'abcd' starts with 'ab'
'abab' ends with 'ab'
'ab' first appears in 'abcd' at 1
'ab' appears in 'abab' 2 times

ALGOL 68

Translation of: python
Works with: ALGOL 68 version Revision 1 - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny

<lang algol68># 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 #

))</lang> Output:

TFFT         -1         +1         +3

AutoHotkey

<lang AutoHotkey> 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%".

</lang>

BASIC

Works with: QBasic

<lang qbasic>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

</lang>

Output:

'qwertyuiop' starts with 'qwerty'
'qwertyuiop' contains 'wert' at position  2
'qwertyuiop' does not end with 'random garbage'

BBC BASIC

<lang bbcbasic> 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%

</lang> Output:

"The fox jumps over the dog" starts with "The"
"The fox jumps over the dog" contains "The" at position 1
"The fox jumps over the dog" contains "The" 1 time(s)
"The fox jumps over the dog" contains "he" at position 2
"The fox jumps over the dog" contains "he" 2 time(s)
"The fox jumps over the dog" ends with "dog"
"The fox jumps over the dog" contains "dog" at position 24
"The fox jumps over the dog" contains "dog" 1 time(s)

Bracmat

Bracmat does pattern matching in expressions subject:pattern and in strings @(subject:pattern). The (sub)pattern ? is a wild card. <lang>( (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'")
 )

)</lang> In the last line, Bracmat is forced by the always failing node ~ to backtrack until all occurrences of 'be' are found. Thereafter the pattern match expression fails. The interesting part is the side effect: while backtracking, the accumulator N keeps track of how many are found.

Output: <lang>sentence starts with 'I' sentence contains 'such' sentence ends with 'even.' sentence contains 3 occurrences of 'be'</lang>

C

Case sensitive matching: <lang C>#include <string.h>

  1. include <stdio.h>

int startsWith(char* container, char* target) {

 size_t clen = strlen(container), tlen = strlen(target);
 if (clen < tlen)
   return 0;
 return strncmp(container, target, tlen) == 0;

}

int endsWith(char* container, 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(char* container, 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;

}</lang> Output :

Starts with Test ( Hello,Hell ) : 1
Ends with Test ( Code,ode ) : 1
Contains Test ( Google,msn ) : 0

Code without using string library to demonstrate how char strings are just pointers: <lang C>#include <stdio.h>

/* returns 0 if no match, 1 if matched, -1 if matched and at end */ int s_cmp(char *a, char *b) {

       char c1 = 0, c2 = 0;
       while (c1 == c2) {
               c1 = *(a++);
               if ('\0' == (c2 = *(b++)))
                       return c1 == '\0' ? -1 : 1;
       }
       return 0;

}

/* returns times matched */ int s_match(char *a, char *b) {

       int i = 0, count = 0;
       printf("matching `%s' with `%s':\n", a, b);
       while (a[i] != '\0') {
               switch (s_cmp(a + i, b)) {
               case -1:
                       printf("matched: pos %d (at end)\n\n", i);
                       return ++count;
               case 1:
                       printf("matched: pos %d\n", i);
                       ++count;
                       break;
               }
               i++;
       }
       printf("end match\n\n");
       return count;

}

int main() {

       s_match("A Short String", "ort S");
       s_match("aBaBaBaBa", "aBa");
       s_match("something random", "Rand");
       return 0;

}</lang>

Output:

matching `A Short String' with `ort S':
matched: pos 4
end match

matching `aBaBaBaBa' with `aBa':
matched: pos 0
matched: pos 2
matched: pos 4
matched: pos 6 (at end)

matching `something random' with `Rand':
end match

C++

<lang cpp>#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</lang>

C#

Works with: Mono version 2.6

<lang csharp> 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 } } </lang>

Clojure

Translation of: Java

<lang clojure>(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])</lang>

CoffeeScript

This example uses string slices, but a better implementation might use indexOf for slightly better performance.

<lang coffeescript> 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] </lang>

D

<lang d>import std.stdio, std.algorithm ; void main() {

   writeln("abcd".startsWith("ab")) ;  // true
   writeln("abcd".endsWith("zn")) ;    // false
   writeln("abab".find("bb")) ;        // empty array (no match)
   writeln("abcd".find("bc")) ;        // "bcd" (substring start at match)
   writeln("abab".indexOf("bb")) ;     // -1 (no match)
   writeln("abab".indexOf("ba")) ;     //  1 (index of 1st match)
   // above function from algorithm module not only work for string but
   // also other array and range
   writeln([1,2,3].indexOf(3)) ;       //  2
   writeln([1,2,3].indexOf([2,3])) ;   //  1

}</lang>

Delphi

<lang Delphi>program CharacterMatching;

{$APPTYPE CONSOLE}

uses StrUtils;

begin

 WriteLn(AnsiStartsText('ab', 'abcd')); // True
 WriteLn(AnsiEndsText('zn', 'abcd')); // False
 WriteLn(AnsiContainsText('abcd', 'bb')); // False
 Writeln(AnsiContainsText('abcd', 'ab')); // True
 WriteLn(Pos('ab', 'abcd')); // 1

end.</lang>

E

<lang e>def f(string1, string2) {

   println(string1.startsWith(string2))
   
   var index := 0
   while ((index := string1.startOf(string2, index)) != -1) {
       println(`at $index`)
       index += 1
   }
   println(string1.endsWith(string2))

}</lang>

Euphoria

<lang euphoria>sequence first, second integer x

first = "qwertyuiop"

-- Determining if the first string starts with second string second = "qwerty" if match(second, first) = 1 then

   printf(1, "'%s' starts with '%s'\n", {first, second})

else

   printf(1, "'%s' does not start with '%s'\n", {first, 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 = match(second, first) if x then

   printf(1, "'%s' contains '%s' at position %d\n", {first, second, x})

else

   printf(1, "'%s' does not contain '%s'\n", {first, second})

end if

-- Determining if the first string ends with the second string second = "uio" if length(second)<=length(first) and match_from(second, first, length(first)-length(second)+1) then

   printf(1, "'%s' ends with '%s'\n", {first, second})

else

   printf(1, "'%s' does not end with '%s'\n", {first, second})

end if</lang>

Output:

'qwertyuiop' starts with 'qwerty'
'qwertyuiop' contains 'wert' at position 2
'qwertyuiop' does not end with 'uio'

Fantom

Fantom provides several self-explanatory string-matching methods:

  • startsWith
  • endsWith
  • contains
  • index (takes an optional index, for the start position)
  • indexIgnoreCase (like above, ignoring case for ASCII characters)
  • indexr (start search from end of string, with an optional index)
  • indexrIgnoreCase (like above, ignoring case for ASCII characters)

<lang fantom> class Main {

 public static Void main ()
 {
   string := "Fantom Language"
   echo ("String is: " + string)
   echo ("does string start with 'Fantom'? " + string.startsWith("Fantom"))
   echo ("does string start with 'Language'? " + string.startsWith("Language"))
   echo ("does string contain 'age'? " + string.contains("age"))
   echo ("does string contain 'page'? " + string.contains("page"))
   echo ("does string end with 'Fantom'? " + string.endsWith("Fantom"))
   echo ("does string end with 'Language'? " + string.endsWith("Language"))
   echo ("Location of 'age' is: " + string.index("age"))
   posn := string.index ("an")
   echo ("First location of 'an' is: " + posn)
   posn = string.index ("an", posn+1)
   echo ("Second location of 'an' is: " + posn)
   posn = string.index ("an", posn+1)
   if (posn == null) echo ("No third location of 'an'")
 }

} </lang>

Output:

String is: Fantom Language
does string start with 'Fantom'? true
does string start with 'Language'? false
does string contain 'age'? true
does string contain 'page'? false
does string end with 'Fantom'? false
does string end with 'Language'? true
Location of 'age' is: 12
First location of 'an' is: 1
Second location of 'an' is: 8
No third location of 'an'

Forth

<lang forth>: starts-with ( a l a2 l2 -- ? )

 tuck 2>r min 2r> compare 0= ;
ends-with ( a l a2 l2 -- ? )
 tuck 2>r negate over + 0 max /string 2r> compare 0= ;

\ use SEARCH ( a l a2 l2 -- a3 l3 ? ) for contains</lang>

GML

Translation of: BASIC

<lang GML>#define charMatch {

   first = "qwertyuiop";
   // Determining if the first string starts with second string 
   second = "qwerty";
   if (string_pos(second, first) > 0) {
       show_message("'" + first + "' starts with '" + second + "'");
   } else {
       show_message("'" + first + "' does not start with '" + second + "'");
   }
   second = "wert"
   // Determining if the first string contains the second string at any location
   // Print the location of the match for part 2
   if (string_pos(second, first) > 0) {
       show_message("'" + first + "' contains '" + second + "' at position " + string(x));
   } else {
       show_message("'" + first + "' does not contain '" + second + "'");
   }
   // Handle multiple occurrences of a string for part 2.
   x = string_count(second, first);
   show_message("'" + first + "' contains " + string(x) + " instances of '" + second + "'");

// Determining if the first string ends with the second string

   second = "random garbage"
   temp = string_copy(first,
                      (string_length(first) - string_length(second)) + 1, 
                      string_length(second));
   if (temp == second) {
       show_message("'" + first + "' ends with '" + second + "'");
   } else {
       show_message("'" + first + "' does not end with '" + second + "'");
   }

}</lang>

Output (in message boxes, 1 per line):

'qwertyuiop' starts with 'qwerty'
'qwertyuiop' contains 'wert' at position 0
'qwertyuiop' contains 1 instances of 'wert'
'qwertyuiop' does not end with 'random garbage'

Go

<lang go>package main

import (

   "fmt"
   "strings"

)

func match(first, second string) {

   fmt.Printf("1. %s starts with %s: %t\n",
       first, second, strings.HasPrefix(first, second))
   i := strings.Index(first, second)
   fmt.Printf("2. %s contains %s: %t,\n", first, second, i >= 0)
   if i >= 0 {
       fmt.Printf("2.1. at location %d,\n", i)
       for start := i+1;; {
           if i = strings.Index(first[start:], second); i < 0 {
               break
           }
           fmt.Printf("2.2. at location %d,\n", start+i)
           start += i+1
       }
       fmt.Println("2.2. and that's all")
   }
   fmt.Printf("3. %s ends with %s: %t\n",
       first, second, strings.HasSuffix(first, second))

}

func main() {

   match("abracadabra", "abr")

}</lang> Output:

1. abracadabra starts with abr: true
2. abracadabra contains abr: true,
2.1. at location 0,
2.2. at location 7,
2.2. and that's all
3. abracadabra ends with abr: false

Haskell

<lang haskell>> import Data.List > "abc" `isPrefixOf` "abcdefg" True > "efg" `isSuffixOf` "abcdefg" True > "bcd" `isInfixOf` "abcdefg" True > "abc" `isInfixOf` "abcdefg" -- Prefixes and suffixes are also infixes True > let infixes a b = map fst $ filter (isPrefixOf a . snd) $ zip [0..] $ tails b > infixes "ab" "abcdefabqqab" [0,6,10]</lang>

Icon and Unicon

<lang Icon>procedure main()

  write("Matching s2 :=",image(s2 := "ab")," within s1:= ",image(s1 := "abcdabab"))

  write("Test #1 beginning ",if match(s2,s1) then "matches " else "failed")
  writes("Test #2 all matches at positions [") 
     every writes(" ",find(s2,s1)|"]\n")
  write("Test #3 ending ", if s1[0-:*s2] == s2 then "matches" else "fails")
  

end</lang>

Sample output:

Matching s2 :="ab" within s1:= "abcdabab"
Test #1 beginning matches
Test #2 all matches at positions [ 1 5 7 ]
Test #3 ending matches

J

<lang j>startswith=: ] -: ({.~ #) contains=: +./@:E.~ endswith=: ] -: ({.~ -@#)</lang>

Example use:

<lang j> 'abcd' startswith 'ab' 1

  'abcd' startswith 'cd'

0

  'abcd' endswith 'ab'

0

  'abcd' endswith 'cd'

1

  'abcd' contains 'bb'

0

  'abcd' contains 'ab'

1

  'abcd' contains 'bc'

1

  'abab' contains 'ab'

1

  'abab' I.@E.~ 'ab'       NB. find starting indicies

0 2</lang>

Note that these verbs contain no constraints restricting them to sequences of characters and so also apply to arrays of type other than character: <lang j> 0 1 2 3 startswith 0 1 NB. integer 1

  4.2 5.1 1.3 9 3 contains 1.3 4.2     NB. floating point

0

  4.2 5.1 1.3 4.2 9 3 contains 1.3 4.2 

1</lang>

Java

<lang java>"abcd".startsWith("ab") //returns true "abcd".endsWith("zn") //returns false "abab".contains("bb") //returns false "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</lang>

JavaScript

<lang javascript>var stringA = "tacoloco"

 , stringB = "co"
 , q1, q2, q2multi, m
 , q2matches = []

// stringA starts with stringB q1 = stringA.substring(0, stringB.length) == stringB

// stringA contains stringB q2 = stringA.indexOf(stringB)

// multiple matches q2multi = new RegExp(stringB,'g')

while(m = q2multi.exec(stringA)){ q2matches.push(m.index) }

// stringA ends with stringB q3 = stringA.substr(-stringB.length) == stringB

console.log("1: Does '"+stringA+"' start with '"+stringB+"'? " + ( q1 ? "Yes." : "No.")) console.log("2: Is '"+stringB+"' contained in '"+stringA+"'? " + (~q2 ? "Yes, at index "+q2+"." : "No.")) if (~q2 && q2matches.length > 1){ console.log(" In fact, it happens "+q2matches.length+" times within '"+stringA+"', at index"+(q2matches.length > 1 ? "es" : "")+" "+q2matches.join(', ')+".") } console.log("3: Does '"+stringA+"' end with '"+stringB+"'? " + ( q3 ? "Yes." : "No."))</lang>

Output:

1: Does 'tacoloco' start with 'co'? No.
2: Is 'co' contained in 'tacoloco'? Yes, at index 2.
   In fact, it happens 2 times within 'tacoloco', at indexes 2, 6.
3: Does 'tacoloco' end with 'co'? Yes.

K

<lang k>startswith: {:[0<#p:_ss[x;y];~*p;0]} endswith: {0=(-#y)+(#x)-*_ss[x;y]} contains: {0<#_ss[x;y]}</lang>

Example:

<lang k> startswith["abcd";"ab"] 1

 startswith["abcd";"bc"]

0

 endswith["abcd";"cd"]

1

 endswith["abcd";"bc"]

0

 contains["abcdef";"cde"]

1

 contains["abcdef";"bdef"]

0

 _ss["abcdabceabc";"abc"]    / location of matches

0 4 8</lang>

LabVIEW

These images solve the task's requirements in order.
This image is a VI Snippet, an executable image of LabVIEW code. The LabVIEW version is shown on the top-right hand corner. You can download it, then drag-and-drop it onto the LabVIEW block diagram from a file browser, and it will appear as runnable, editable code.


Liberty BASIC

<lang lb>'1---Determining if the first string starts with second string st1$="first string" st2$="first" if left$(st1$,len(st2$))=st2$ then

   print "First string starts with second string."

end if

'2---Determining if the first string contains the second string at any location '2.1---Print the location of the match for part 2 st1$="Mississippi" st2$="i" if instr(st1$,st2$) then

   print "First string contains second string."
   print "Second string is at location ";instr(st1$,st2$)

end if

'2.2---Handle multiple occurrences of a string for part 2. pos=instr(st1$,st2$) while pos

   count=count+1
   pos=instr(st1$,st2$,pos+len(st2$))

wend print "Number of times second string appears in first string is ";count

'3---Determining if the first string ends with the second string st1$="first string" st2$="string" if right$(st1$,len(st2$))=st2$ then

   print "First string ends with second string."

end if

</lang>

<lang logo>to starts.with? :sub :thing

 if empty? :sub [output "true]
 if empty? :thing [output "false]
 if not equal? first :sub first :thing [output "false]
 output starts.with? butfirst :sub butfirst :thing

end

to ends.with? :sub :thing

 if empty? :sub [output "true]
 if empty? :thing [output "false]
 if not equal? last :sub last :thing [output "false]
 output ends.with? butlast :sub butlast :thing

end

show starts.with? "dog "doghouse  ; true show ends.with? "house "doghouse  ; true show substring? "gho "doghouse  ; true (built-in)</lang>

Lua

<lang lua>s1 = "string" s2 = "str" s3 = "ing" s4 = "xyz"

print( "s1 starts with s2: ", string.find( s1, s2 ) == 1 ) print( "s1 starts with s3: ", string.find( s1, s3 ) == 1, "\n" )

print( "s1 contains s3: ", string.find( s1, s3 ) ~= nil ) print( "s1 contains s3: ", string.find( s1, s4 ) ~= nil, "\n" )

print( "s1 ends with s2: ", select( 2, string.find( s1, s2 ) ) == string.len( s1 ) ) print( "s1 ends with s3: ", select( 2, string.find( s1, s3 ) ) == string.len( s1 ) )</lang>

Mathematica

<lang Mathematica>StartWith[x_, y_] := MemberQ[Flatten[StringPosition[x, y]], 1] EndWith[x_, y_] := MemberQ[Flatten[StringPosition[x, y]], StringLength[x]] StartWith["XYZaaabXYZaaaaXYZXYZ", "XYZ"] EndWith["XYZaaabXYZaaaaXYZXYZ", "XYZ"] StringPosition["XYZaaabXYZaaaaXYZXYZ", "XYZ"]</lang>

Output

True
True
{{1,3},{8,10},{15,17},{18,20}}


MATLAB / Octave

<lang Matlab>

  % 1. Determining if the first string starts with second string

strcmp(str1,str2,length(str2))

  % 2. Determining if the first string contains the second string at any location

~isempty(strfind(s1,s2))

  % 3. Determining if the first string ends with the second string 

( (length(str1)>=length(str2)) && strcmp(str1(end+[1-length(str2):0]),str2) )

  % 1. Print the location of the match for part 2

disp(strfind(s1,s2))

  % 2. Handle multiple occurrences of a string for part 2. 

ix = strfind(s1,s2);  % ix is a vector containing the starting positions of s2 within s1 </lang>


NetRexx

<lang NetRexx>/* NetRexx */ options replace format comments java crossref savelog symbols

lipsum = x_ = 0 x_ = x_ + 1; lipsum[0] = x_; lipsum[x_] = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' x_ = x_ + 1; lipsum[0] = x_; lipsum[x_] = lipsum[1].reverse

srch = srch[1] = 'Lorem ipsum dolor sit amet' srch[2] = 'consectetur adipisicing elit' srch[3] = 'dolore magna aliqua.'

loop j_ = 1 to lipsum[0]

 x1 = lipsum[j_].pos(srch[1])
 x2 = lipsum[j_].pos(srch[2])
 x3 = lipsum[j_].lastpos(srch[3])
 report(x1 = 1, lipsum[j_], srch[1], 'Test string starts with search string:', 'Test string does not start with search string:')
 report(x2 > 0, lipsum[j_], srch[2], 'Search string located in test string at position:' x2,  'Search string not found within test string:')
 report(x3 \= srch[3].length, lipsum[j_], srch[3], 'Test string ends with search string:', 'Test string does not start with search string:')
 end j_

many = x_ = 0 x_ = x_ + 1; many[0] = x_; many[x_] = 'How many times does "many times" occur in this string?' x_ = x_ + 1; many[0] = x_; many[x_] = 'How often does "many times" occur in this string?' x_ = x_ + 1; many[0] = x_; many[x_] = 'How often does it occur in this string?' srch[4] = 'many times'

loop j_ = 1 to many[0]

 o_ = 0
 k_ = 0
 loop label dups until o_ = 0
   o_ = many[j_].pos(srch[4], o_ + 1)
   if o_ \= 0 then k_ = k_ + 1
   end dups
 report(k_ > 0, many[j_], srch[4], 'Number of times search string occurs:' k_, 'Search string not found')
 end j_

method report(state = boolean, ts, ss, testSuccess, testFailure) public static

 if state then say testSuccess
 else          say testFailure
 say '    Test string:' ts
 say '  Search string:' ss
 say
 return

</lang>


Objective-C

<lang objc>[@"abcd" hasPrefix:@"ab"] //returns true [@"abcd" hasSuffix:@"zn"] //returns false int loc = [@"abab" rangeOfString:@"bb"].location //returns -1 loc = [@"abab" rangeOfString:@"ab"].location //returns 0 loc = [@"abab" rangeOfString:@"ab" options:0 range:NSMakeRange(loc+1, [@"abab" length]-(loc+1))].location //returns 2</lang>

Objeck

<lang objeck> bundle Default {

 class Matching {
   function : Main(args : System.String[]) ~ Nil {
     "abcd"->StartsWith("ab")->PrintLine(); # returns true
     "abcd"->EndsWith("zn")->PrintLine(); # returns false
     ("abab"->Find("bb") <> -1)->PrintLine(); # returns false
     ("abab"->Find("ab") <> -1)->PrintLine(); # returns true
     loc := "abab"->Find("bb"); # returns -1
     loc := "abab"->Find("ab"); # returns 0
     loc := "abab"->Find("ab", loc + 1); # returns 2
   }
 }

} </lang>

OCaml

<lang ocaml>let match1 s1 s2 =

 let len1 = String.length s1
 and len2 = String.length s2 in
 if len1 < len2 then false else
   let sub = String.sub s1 0 len2 in
   (sub = s2)</lang>

testing in the top-level:

# match1 "Hello" "Hello World!" ;;
- : bool = false
# match1 "Hello World!" "Hello" ;;
- : bool = true

<lang ocaml>let match2 s1 s2 =

 let len1 = String.length s1
 and len2 = String.length s2 in
 if len1 < len2 then false else
   let rec aux i =
     if i < 0 then false else
       let sub = String.sub s1 i len2 in
       if (sub = s2) then true else aux (pred i)
   in
   aux (len1 - len2)</lang>
# match2 "It's raining, Hello World!" "umbrella" ;;
- : bool = false
# match2 "It's raining, Hello World!" "Hello" ;;
- : bool = true

<lang ocaml>let match3 s1 s2 =

 let len1 = String.length s1
 and len2 = String.length s2 in
 if len1 < len2 then false else
   let sub = String.sub s1 (len1 - len2) len2 in
   (sub = s2)</lang>
# match3 "Hello World" "Hello" ;;
- : bool = false
# match3 "Hello World" "World" ;;
- : bool = true

<lang ocaml>let match2_loc s1 s2 =

 let len1 = String.length s1
 and len2 = String.length s2 in
 if len1 < len2 then (false, -1) else
   let rec aux i =
     if i < 0 then (false, -1) else
       let sub = String.sub s1 i len2 in
       if (sub = s2) then (true, i) else aux (pred i)
   in
   aux (len1 - len2)</lang>
# match2_loc "The sun's shining, Hello World!" "raining" ;;
- : bool * int = (false, -1)
# match2_loc "The sun's shining, Hello World!" "shining" ;;
- : bool * int = (true, 10)

<lang ocaml>let match2_num s1 s2 =

 let len1 = String.length s1
 and len2 = String.length s2 in
 if len1 < len2 then (false, 0) else
   let rec aux i n =
     if i < 0 then (n <> 0, n) else
       let sub = String.sub s1 i len2 in
       if (sub = s2)
       then aux (pred i) (succ n)
       else aux (pred i) (n)
   in
   aux (len1 - len2) 0</lang>
# match2_num "This cloud looks like a camel, \
    that other cloud looks like a llama" "stone" ;;
- : bool * int = (false, 0)
# match2_num "This cloud looks like a camel, \
    that other cloud looks like a llama" "cloud" ;;
- : bool * int = (true, 2)

PARI/GP

This meets the first but not the second of the optional requirements. Note that GP treats any nonzero value as true so the location found by contains() can be ignore if not needed. <lang parigp>startsWith(string, prefix)={

 string=Vec(string);
 prefix=Vec(prefix);
 if(#prefix > #string, return(0));
 for(i=1,#prefix,if(prefix[i]!=string[i], return(0)));
 1

}; contains(string, inner)={

 my(good);
 string=Vec(string);
 inner=Vec(inner);
 for(i=0,#string-#inner,
   good=1;
   for(j=1,#inner,
     if(inner[j]!=string[i+j], good=0; break)
   );
   if(good, return(i+1))
 );
 0

}; endsWith(string, suffix)={

 string=Vec(string);
 suffix=Vec(suffix);
 if(#suffix > #string, return(0));
 for(i=1,#suffix,if(prefix[i]!=string[i+#string-#suffix], return(0)));
 1

};</lang>

Perl

<lang perl># the first four examples use regular expressions, so make sure to escape any special regex characters in the substring "abcd" =~ /^ab/ #returns true "abcd" =~ /zn$/ #returns false "abab" =~ /bb/ #returns false "abab" =~ /ab/ #returns true my $loc = index("abab", "bb") #returns -1 $loc = index("abab", "ab") #returns 0 $loc = index("abab", "ab", $loc+1) #returns 2</lang>

Perl 6

<lang perl6>my @subs = (

   # Regex-based:
   sub R_contains    ( Str $_, Str $s2 ) { ? m/   $s2   / },
   sub R_starts_with ( Str $_, Str $s2 ) { ? m/ ^ $s2   / },
   sub R_ends_with   ( Str $_, Str $s2 ) { ? m/   $s2 $ / },
   # Index-based:
   sub I_contains    ( Str $_, Str $s2 ) {         .index( $s2)\   .defined },
   sub I_starts_with ( Str $_, Str $s2 ) { my $m = .index( $s2); $m.defined and $m == 0 },
   sub I_ends_with   ( Str $_, Str $s2 ) { my $m = .rindex($s2); $m.defined and $m == .chars - $s2.chars },
   # Substr-based:
   sub S_starts_with ( Str $_, Str $s2 ) { .substr(0, $s2.chars) eq $s2 },
   sub S_ends_with   ( Str $_, Str $s2 ) { .substr(  -$s2.chars) eq $s2 },
   # Optional tasks:
   sub R_find        ( Str $_, Str $s2 ) { $/.from if /$s2/ },
   sub R_find_all    ( Str $_, Str $s2 ) {
       my @p = .match: /$s2/, :g;
       @p».from if @p;
   },

);

my $str1 = 'abcbcbcd'; my @str2s = < ab bc cd zz >;

say "'$str1' vs:".fmt('%15s '), @str2s.fmt('%-15s'); for [1, 4, 6], [2, 5, 7], [0, 3], [8, 9] {

   say;
   for @subs[.list] -> $sub {
       say "{$sub.name}:".fmt('%15s '),
           @str2s.map({ ~$sub.($str1, $_) }).fmt('%-15s');
   }

}</lang>

Output:

 'abcbcbcd' vs: ab              bc              cd              zz             

 R_starts_with: Bool::True      Bool::False     Bool::False     Bool::False    
 I_starts_with: Bool::True      Bool::False     Bool::False     Bool::False    
 S_starts_with: Bool::True      Bool::False     Bool::False     Bool::False    

   R_ends_with: Bool::False     Bool::False     Bool::True      Bool::False    
   I_ends_with: Bool::False     Bool::False     Bool::True      Bool::False    
   S_ends_with: Bool::False     Bool::False     Bool::True      Bool::False    

    R_contains: Bool::True      Bool::True      Bool::True      Bool::False    
    I_contains: Bool::True      Bool::True      Bool::True      Bool::False    

        R_find: 0               1               6               Nil()          
    R_find_all: 0               1 3 5           6               Nil()          

PicoLisp

<lang PicoLisp>: (pre? "ab" "abcd") -> "abcd"

(pre? "xy" "abcd")

-> NIL

(sub? "bc" "abcd")

-> "abcd"

(sub? "xy" "abcd")

-> NIL

(tail (chop "cd") (chop "abcd"))

-> ("c" "d")

(tail (chop "xy") (chop "abcd"))

-> NIL


(de positions (Pat Str)

  (setq Pat (chop Pat))
  (make
     (for ((I . L) (chop Str) L (cdr L))
        (and (head Pat L) (link I)) ) ) )
(positions "bc" "abcdabcd")

-> (2 6)</lang>

PL/I

<lang PL/I> /* Let s be one string, t be the other that might exist within s. */

                                                    /* 8-1-2011 */

k = index(s, t); if k = 0 then put skip edit (t, ' is nowhere in sight') (a); else if k = 1 then

  put skip edit (t, '  starts at the beginning of  ', s) (a);

else if k+length(t)-1 = length(s) then

  put skip edit (t, '  is at the end of  ', s) (a);

else put skip edit (t, ' is within ', s) (a);

if k > 0 then put skip edit (t, ' starts at position ', k) (a); </lang>

Optional extra:

<lang PL/I> /* Handle multiple occurrences. */

  n = 1;
  do forever;
     k = index(s, t, n);
     if k = 0 then
        do;
           if n = 1 then put skip list (t, ' is nowhere in sight');
           stop;
        end;
     else if k = 1 then
        put skip edit ('<', t, '> starts at the beginning of  ', s) (a);
     else if k+length(t)-1 = length(s) then
        put skip edit ('<', t, '> is at the end of  ', s) (a);
     else put skip edit ('<', t, '> is within  ', s) (a);
     n =   k + length(t);
     if k > 0 then
        put skip edit ('<', t, '> starts at position ', trim(k)) (a);
     else stop;
  end;

</lang>

PureBasic

<lang PureBasic>Procedure StartsWith(String1$, String2$)

 Protected Result
 If FindString(String1$, String2$, 1) =1 ; E.g Found in possition 1
   Result =CountString(String1$, String2$)
 EndIf
 ProcedureReturn Result

EndProcedure

Procedure EndsWith(String1$, String2$)

 Protected Result, dl=Len(String1$)-Len(String2$)
 If dl>=0 And Right(String1$, Len(String2$))=String2$
   Result =CountString(String1$, String2$)
 EndIf
 ProcedureReturn Result

EndProcedure</lang> And a verification <lang PureBasic>If OpenConsole()

 PrintN(Str(StartsWith("Rosettacode", "Rosetta")))           ; = 1
 PrintN(Str(StartsWith("Rosettacode", "code")))              ; = 0
 PrintN(Str(StartsWith("eleutherodactylus cruralis", "e")))  ; = 3
 PrintN(Str(EndsWith  ("Rosettacode", "Rosetta")))  ; = 0
 PrintN(Str(EndsWith  ("Rosettacode", "code")))     ; = 1
 PrintN(Str(EndsWith  ("Rosettacode", "e")))        ; = 2
 
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
 CloseConsole()

EndIf</lang>

An alternate and more complete solution: <lang PureBasic>Procedure startsWith(string1$, string2$)

 ;returns one if string1$ starts with string2$, otherwise returns zero
 If FindString(string1$, string2$, 1) = 1
   ProcedureReturn 1
 EndIf 
 ProcedureReturn 0

EndProcedure

Procedure contains(string1$, string2$, location = 0)

 ;returns the location of the next occurrence of string2$ in string1$ starting from location,
 ;or zero if no remaining occurrences of string2$ are found in string1$
 ProcedureReturn FindString(string1$, string2$, location + 1)

EndProcedure

Procedure endsWith(string1$, string2$)

 ;returns one if string1$ ends with string2$, otherwise returns zero
 Protected ls = Len(string2$)
 If Len(string1$) - ls >= 0 And Right(string1$, ls) = string2$
   ProcedureReturn 1
 EndIf
 ProcedureReturn 0

EndProcedure

If OpenConsole()

 PrintN(Str(startsWith("RosettaCode", "Rosetta")))           ; = 1, true
 PrintN(Str(startsWith("RosettaCode", "Code")))              ; = 0, false
 
 PrintN("")
 PrintN(Str(contains("RosettaCode", "luck")))                ; = 0, no occurrences
 Define location
 Repeat
   location = contains("eleutherodactylus cruralis", "e", location)
   PrintN(Str(location))                                     ;display each occurrence: 1, 3, 7,  & 0 (no more occurrences)
 Until location = 0
 
 PrintN("")
 PrintN(Str(endsWith  ("RosettaCode", "Rosetta")))            ; = 0, false
 PrintN(Str(endsWith  ("RosettaCode", "Code")))               ; = 1, true
  
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
 CloseConsole()

EndIf</lang> Sample output:

1
0

0
1
3
7
0

0
1

PowerShell

<lang Powershell> "spicywiener".StartsWith("spicy") "spicywiener".Contains("icy") "spicywiener".EndsWith("wiener") "spicywiener".IndexOf("icy") [regex]::Matches("spicywiener", "i").count </lang> Output:

True
True
True
2
2

Python

<lang python>"abcd".startswith("ab") #returns true "abcd".endswith("zn") #returns false "bb" in "abab" #returns false "ab" in "abab" #returns true loc = "abab".find("bb") #returns -1 loc = "abab".find("ab") #returns 0 loc = "abab".find("ab",loc+1) #returns 2</lang>

Retro

<lang Retro>: startsWith? ( $1 $2 - f )

 withLength &swap dip 0 swap ^strings'getSubset compare ;

"abcdefghijkl" "abcde" startsWith? "abcdefghijkl" "bcd" startsWith?

"abcdefghijkl" "bcd" ^strings'search "abcdefghijkl" "zmq" ^strings'search

endsWith? ( $1 $2 - f )
 swap withLength + over getLength - compare ;

"abcdefghijkl" "ijkl" endsWith? "abcdefghijkl" "abc" endsWith?</lang>

REXX

Extra coding was added to take of using plurals in the messages. <lang rexx> /*REXX program to show some basic character string testing. */

parse arg a b

say 'string A=' a say 'string B=' b say

if left(A,length(b))==b then say 'string A starts with string B'

                       else say "string A doesn't start with string B"

say

p=pos(b,a) if p\==0 then say 'string A contains string B (starting in position' p")"

        else say "string A doesn't contains string B"

say

if right(A,length(b))==b then say 'string A ends with string B'

                        else say "string A doesn't end with string B"

say

Ps= p=0

 do forever until p==0
 p=pos(b,a,p+1)
 if p\==0 then Ps=Ps',' p
 end

Ps=space(strip(Ps,'L',",")) times=words(Ps) if times\==0 then say 'string A contains string B',

                     times 'time'left('s',times>1),
                     "(at position"left('s',times>1) Ps')'
            else say "string A doesn't contains string B"

</lang> Output when the following is specified (five Marx brothers):

Chico_Harpo_Groucho_Zeppo_Gummo p

string A= Chico_Harpo_Groucho_Zeppo_Gummo
string B= p

string A doesn't start with string B

string A contains string B (starting in position 10)

string A doesn't end with string B

string A contains string B 3 times (at positions 10, 23, 24)

Output when the following is specified:

Chico_Harpo_Groucho_Zeppo_Gummo Z

string A= Chico_Harpo_Groucho_Zeppo_Gummo
string B= Z

string A doesn't start with string B

string A contains string B (starting in position 21)

string A doesn't end with string B

string A contains string B 1 time (at position 21)

Output when the following is specified:

Chico_Harpo_Groucho_Zeppo_Gummo Chi

string A= Chico_Harpo_Groucho_Zeppo_Gummo
string B= Chi

string A starts with string B

string A contains string B (starting in position 1)

string A doesn't end with string B

string A contains string B 1 time (at position 1)

Output when the following is specified:

Chico_Harpo_Groucho_Zeppo_Gummo mmo

string A= Chico_Harpo_Groucho_Zeppo_Gummo
string B= mmo

string A doesn't start with string B

string A contains string B (starting in position 29)

string A ends with string B

string A contains string B 1 time (at position 29)

Ruby

Works with: Ruby version 1.8.7

<lang ruby>'abcd'.start_with?('ab') #returns true 'abcd'.end_with?('zn') #returns false 'abab'.include?('bb') #returns false 'abab'.include?('ab') #returns true 'abab'.index('bb') #returns -1 'abab'.index('ab') #returns 0 'abab'.index('ab', 1) #returns 2</lang>

Scala

<lang scala>"abcd".startsWith("ab") //returns true "abcd".endsWith("zn") //returns false "abab".contains("bb") //returns false "abab".contains("ab") //returns true

var loc="abab".indexOf("bb") //returns -1 loc = "abab".indexOf("ab") //returns 0 loc = "abab".indexOf("ab", loc+1) //returns 2</lang>

Seed7

<lang seed7>$ include "seed7_05.s7i";

const proc: main is func

 local
   var integer: position is 0;
 begin
   writeln(startsWith("abcd", "ab")); # write TRUE
   writeln(endsWith("abcd", "zn"));   # write FALSE
   writeln(pos("abab", "bb") <> 0);   # write FALSE
   writeln(pos("abab", "ab") <> 0);   # write TRUE
   writeln(pos("abab", "bb"));        # write 0
   position := pos("abab", "ab");
   writeln(position);                 # position is 1
   position := pos("abab", "ab", succ(position));
   writeln(position);                 # position is 3
 end func;</lang>

Output:

TRUE
FALSE
FALSE
TRUE
0
1
3

Standard ML

<lang sml>String.isPrefix "ab" "abcd"; (* returns true *) String.isSuffix "zn" "abcd"; (* returns false *) String.isSubstring "bb" "abab"; (* returns false *) String.isSubstring "ab" "abab"; (* returns true *)

  1. 2 (Substring.base (#2 (Substring.position "bb" (Substring.full "abab")))); (* returns 4 *)

val loc = #2 (Substring.base (#2 (Substring.position "ab" (Substring.full "abab")))); (* returns 0 *) val loc' = #2 (Substring.base (#2 (Substring.position "ab" (Substring.extract ("abab", loc+1, NONE))))); (* returns 2 *)</lang>

Tcl

In this code, we are looking in various ways for the string in the variable needle in the string in the variable haystack. <lang tcl>set isPrefix [string equal -length [string length $needle] $haystack $needle] set isContained [expr {[string first $needle $haystack] >= 0}] set isSuffix [string equal $needle [string range $haystack end-[expr {[string length $needle]-1}] end]]</lang>

Of course, in the cases where the needle is a glob-safe string (i.e., doesn't have any of the characters “*?[\” in), this can be written far more conveniently: <lang tcl>set isPrefix [string match $needle* $haystack] set isContained [string match *$needle* $haystack] set isSuffix [string match *$needle $haystack]</lang>

Another powerful technique is to use the regular expression engine in literal string mode: <lang tcl>set isContained [regexp ***=$needle $haystack]</lang> This can be extended by getting the regexp to return the locations of the matches, enabling the other forms of match to be done: <lang tcl>set matchLocations [regexp -indices -all -inline ***=$needle $haystack]

  1. Each match location is a pair, being the index into the string where the needle started
  2. to match and the index where the needle finished matching

set isContained [expr {[llength $matchLocations] > 0}] set isPrefix [expr {[lindex $matchLocations 0 0] == 0}] set isSuffix [expr {[lindex $matchLocations end 1] == [string length $haystack]-1}] set firstMatchStart [lindex $matchLocations 0 0] puts "Found \"$needle\" in \"$haystack\" at $firstMatchStart" foreach location $matchLocations {

   puts "needle matched at index [lindex $location 0]"

}</lang>

TUSCRIPT

<lang tuscript> $$ MODE TUSCRIPT ASK "string1", string1="" ASK "string2", string2=""

IF (string1.sw.string2) THEN PRINT string1," starts with ",string2 ELSE PRINT string1," not starts with ",string2 ENDIF SET beg=STRING (string1,string2,0,0,0,end) IF (beg!=0) THEN PRINT string1," contains ",string2 PRINT " starting in position ",beg PRINT " ending in position ",end ELSE PRINT string1," not contains ",string2 ENDIF

IF (string1.ew.string2) THEN PRINT string1," ends with ",string2 ELSE PRINT string1," not ends with ",string2 ENDIF </lang> Output:

string1 >Rosetta Code
string2 >Code
Rosetta Code not starts with Code
Rosetta Code contains        Code
  starting in position 9
  ending   in position 13
Rosetta Code ends with       Code 

TXR

<lang txr>@line @(cases) @ line @ (output) second line is the same as first line @ (end) @(or) @ (skip)@line @ (output) first line is a suffix of the second line @ (end) @(or) @ line@(skip) @ (output) first line is a suffix of the second line @ (end) @(or) @ prefix@line@(skip) @ (output) first line is embedded in the second line at position @(length prefix) @ (end) @(or) @ (output) first line is not found in the second line @ (end) @(end)</lang>

$ txr cmatch.txr -
123
01234
first line is embedded in the second line at position 1
$ txr cmatch.txr -
123
0123
first line is a suffix of the second line