filter items which does not contain a substring

I know how to extract from a list items containing a substring but I prove unable to extract items which doesn’t contain a substring.
May you give me the correct filter to use ?

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

set theSource to ((path to desktop as text) & "Titres m4p 20190704.txt") as «class furl»
set theList to paragraphs of (read theSource)

--set newList to my itemsContaining:"Complete Jazz Series" inList:theList
set newList to my itemsWithout:"Complete Jazz Series" inList:theList
set theResult to my concatList:newList usingString:linefeed

#=====

on itemsContaining:theVal inList:theList
	set theArray to current application's NSArray's arrayWithArray:theList
	set thePred to current application's NSPredicate's predicateWithFormat:"self CONTAINS %@" argumentArray:{theVal}
	return (theArray's filteredArrayUsingPredicate:thePred) as list
end itemsContaining:inList:

#=====

on itemsWithout:theVal inList:theList
	set theArray to current application's NSArray's arrayWithArray:theList
	set thePred to current application's NSPredicate's predicateWithFormat:"self !=,CONTAINS %@" argumentArray:{theVal} # WRONG SYNTAX
	return (theArray's filteredArrayUsingPredicate:thePred) as list
end itemsWithout:inList:

#=====

on concatList:theList usingString:d1
	set anArray to current application's NSArray's arrayWithArray:theList
	return (anArray's componentsJoinedByString:d1) as text
end concatList:usingString:

#=====

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 5 juillet 2019 16:54:13

I found a way to get the wanted result but I am always interested to know the correct filter.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

set theSource to ((path to desktop as text) & "Titres m4p 20190704.txt") as «class furl»
set oldList to paragraphs of (read theSource)

set newList to my itemsContaining:"Complete Jazz Series" inList:oldList
set listWithout to my removeItemsInListInOrder:newList fromList:oldList

return {my concatList:newList usingString:linefeed, my concatList:listWithout usingString:linefeed}

#=====

on itemsContaining:theVal inList:theList
	set theArray to current application's NSArray's arrayWithArray:theList
	set thePred to current application's NSPredicate's predicateWithFormat:"self CONTAINS %@" argumentArray:{theVal}
	return (theArray's filteredArrayUsingPredicate:thePred) as list
end itemsContaining:inList:

#=====

on removeItemsInListInOrder:oldList fromList:newList
	set set2 to current application's NSSet's setWithArray:oldList
	set set1 to current application's NSMutableOrderedSet's orderedSetWithArray:newList
	set1's minusSet:set2
	return (set1's array()) as list
end removeItemsInListInOrder:fromList:

#=====

on concatList:theList usingString:d1
	set anArray to current application's NSArray's arrayWithArray:theList
	return (anArray's componentsJoinedByString:d1) as text
end concatList:usingString:

#=====

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 5 juillet 2019 17:11:35

Hi Yvan.

The predicate string should be either “NOT self CONTAINS %@” or “! self CONTAINS %@”. You can parenthesise the “self CONTAINS %@” part if you like: “NOT (self CONTAINS %@)” or “! (self CONTAINS %@”).

Thanks Nigel, it’s exactly what I wanted.
It’s really fast.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

my Germaine()

on Germaine()
	set p2d to path to desktop as text
	set theSource to (p2d & "Titres m4p 20190704.txt") as «class furl»
	set theList to paragraphs of (read theSource as «class utf8»)
	set startDate to current application's NSDate's |date|()
	set nbRows to count theList
	set newList to my itemsContaining:"Complete Jazz Series" inList:theList
	set listWithout to my itemsWithout:"Complete Jazz Series" inList:theList
	
	set theData to (nbRows as text) & linefeed & "items With" & linefeed & (my concatList:newList usingString:linefeed) & linefeed & "items Without" & linefeed & (my concatList:listWithout usingString:linefeed)
	set targetFile to p2d & "with or without.txt"
	my writeto(targetFile, theData, «class utf8», false)
	
	set timeDiff to startDate's timeIntervalSinceNow()
	display dialog "That took " & (-timeDiff as real) & " seconds."
	
	--> with 21548 lines in the source file  "That took 0,479604959488 seconds."
end Germaine

#=====

on itemsContaining:theVal inList:theList
	set theArray to current application's NSArray's arrayWithArray:theList
	set thePred to current application's NSPredicate's predicateWithFormat:"self CONTAINS %@" argumentArray:{theVal}
	return (theArray's filteredArrayUsingPredicate:thePred) as list
end itemsContaining:inList:

#=====

on itemsWithout:theVal inList:theList
	set theArray to current application's NSArray's arrayWithArray:theList
	set thePred to current application's NSPredicate's predicateWithFormat:"NOT (self CONTAINS %@)" argumentArray:{theVal} # thanks to Nigel Garvey
	return (theArray's filteredArrayUsingPredicate:thePred) as list
end itemsWithout:inList:

#=====

on concatList:theList usingString:d1
	set anArray to current application's NSArray's arrayWithArray:theList
	return (anArray's componentsJoinedByString:d1) as text
end concatList:usingString:

#=====
(*
Handler borrowed to Regulus6633 - http://macscripter.net/viewtopic.php?id=36861
*)
on writeto(targetFile, theData, dataType, apendData)
	-- targetFile is the path to the file you want to write
	-- theData is the data you want in the file.
	-- dataType is the data type of theData and it can be text, list, record etc.
	-- apendData is true to append theData to the end of the current contents of the file or false to overwrite it
	try
		set targetFile to targetFile as «class furl»
		set openFile to open for access targetFile with write permission
		if not apendData then set eof of openFile to 0
		write theData to openFile starting at eof as dataType
		close access openFile
		return true
	on error
		try
			close access targetFile
		end try
		return false
	end try
end writeto

#=====

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 5 juillet 2019 18:25:03

And for the sake of completeness, to make it ignore case you would use “CONTAINS[c]”.

Thanks for this info Shane.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 6 juillet 2019 09:53:46