Split large CSV file into smaller files

Hi there! I have a very long CSV file that is really the combination of multiple tables of data where each table is delineated by a START tag and an END tag. The two tables I am concerned with are called “Levels” and “Targets”. So the file looks like this (with example column headers and data in italics):

START_LEVELS
LEVELS, TABLE, COLUMN, HEADERS
1,1,1,1
2,2,2,2
3,3,3,3

END_LEVELS
START_TARGETS

TARGETS, TABLE, COLUMN, HEADERS, EXAMPLE
4,4,4,4,4
5,5,5,5,5
6,6,6,6,6
7,7,7,7,7

END_TARGETS

I am trying to find a way to programmatically split this file up into multiple individual files with one new smaller file per table. So there would be one new file called “Levels.csv” that contained this:

LEVELS, TABLE, COLUMN, HEADERS
1,1,1,1
2,2,2,2
3,3,3,3

And another new file called “Targets.csv” that contained this:

TARGETS, TABLE, COLUMN, HEADERS, EXAMPLE
4,4,4,4,4
5,5,5,5,5
6,6,6,6,6
7,7,7,7,7

Can I do this with pure AppleScript? Do I need to use AppleScript to control a text editor like TextWrangler? Any guidance would be much appreciated.

Here is one method that is very brute force. It does work on your data.


set csvFile to (choose file with prompt "Select CSV file...") as text
set csvPath to my extractPath(csvFile)

set csvRecords to read file csvFile using delimiter {return}

set levelsFlag to false
set targetsFlag to false

repeat with thisRecord in csvRecords
	set recordItems to my getItems(thisRecord)
	
	if item 1 of recordItems = "END_LEVELS" then
		set levelsFlag to false
		try
			close access file outputFile
		end try
	end if
	if levelsFlag then
		write thisRecord & return to outFileRef
	end if
	if item 1 of recordItems = "START_LEVELS" then
		set levelsFlag to true
		set outputFile to csvPath & "Levels.csv"
		try
			set outFileRef to open for access file outputFile with write permission
		on error
			try
				close access file outputFile
			end try
		end try
	end if
	
	if item 1 of recordItems = "END_TARGETS" then
		set targetsFlag to false
		try
			close access file outputFile
		end try
	end if
	if targetsFlag then
		write thisRecord & return to outFileRef
	end if
	if item 1 of recordItems = "START_TARGETS" then
		set targetsFlag to true
		set outputFile to csvPath & "Targets.csv"
		try
			set outFileRef to open for access file outputFile with write permission
		on error
			try
				close access file outputFile
			end try
		end try
	end if
	
end repeat

on getItems(theRecord)
	copy the text item delimiters to origDelims
	set the text item delimiters to ","
	set recordItems to {}
	set recordItems to every text item of theRecord
	set the text item delimiters to origDelims
	return recordItems
end getItems

on putItems(theRecord)
	copy the text item delimiters to origDelims
	set the text item delimiters to ","
	set recordItems to {}
	set recordItems to every text item of theRecord
	set the text item delimiters to origDelims
	return recordItems
end putItems


on extractPath(theFile)
	set tid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to ":"
	set fileParts to text items of theFile
	set thePath to text items 1 thru -2 of fileParts as text
	set AppleScript's text item delimiters to tid
	set thePath to thePath & ":" as text
	return thePath
end extractPath

Thanks so much for your help! i have opened that code in Script Editor, pressed “Run Script”, and selected my csv file at the prompt but nothing else happens. No new files are created, no nothing. What am I doing wrong?

Here is a script which may treat a source file containing numerous subtables.


set theMainFile to (path to desktop as text) & "main.csv"

with timeout of 20 * 60 seconds # ADDED
	set leTexte to read file theMainFile
end timeout # ADDED

set leTexte to my supprime(leTexte, "START_")
set enListe to my decoupe(leTexte, "END_")
set targetFolder to (path to desktop as text)

repeat with i from 1 to count enListe
	if i = 1 then
		set aSubList to paragraphs 2 thru -2 of item i of enListe
	else if i < (count enListe) then
		set aSubList to paragraphs 3 thru -2 of item i of enListe
	end if
	set aSubList to my recolle(aSubList, return)
	set nameOfSubList to item 1 of my decoupe(aSubList, ",")
	set fpath to targetFolder & nameOfSubList & ".csv"
	my writeto(fpath, aSubList, text, false)
end repeat

#=====

on decoupe(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

#=====

on recolle(l, d)
	local oTIDs, t
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end recolle

#=====
(*
removes every occurences of d in text t
*)
on supprime(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to ""
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end supprime

#=====
(*
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 text
		set openFile to open for access file 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 file targetFile
		end try
		return false
	end try
end writeto

#=====

As is, the file names are in uppercase.
Is it a problem ?

Yvan KOENIG (VALLAURIS, France) lundi 15 décembre 2014 21:36:59

Thanks, Yvan! This is working great on my small test file. And uppercase filenames is not a problem at all. The only issue is, the main .csv files will often be over 100,000 lines. I started the script a few minutes ago on an actual file, and it’s still running… I don’t know how long it might go for… Any way to do this more quickly?

The script is designed to read the entire file once.
If your file is 100,000 lines longs, I am not sure that it may be done.
Open the application “Activity Monitor” which is in the folder “Applications:Utilities”
Ask it to display the Disk activity.
Select the process named “Script Editor”
look if the script is really reading on the disk.

I edited the script above adding a with timeout block.

If it’s not sufficient, I will edit it asking it to read the file by chunks.
May you give an estimation of the size of the larger sublist ?

No need to hurry, I am ready to switch off.
I will be back tomorrow.

Yvan KOENIG (VALLAURIS, France) lundi 15 décembre 2014 22:23:04

Yvan is one of the resident geniuses. Use his code.

Again, mine worked on the sample data you provided. At least I created some great subroutines for my own use.

Best,
:slight_smile:

I’m not a genius, just a pig headed user which dislike when he don’t find an answer.
As you didn’t respond to my question, I assumed that there is no list descriptor whose length is greater than 10000 characters.

# Define the path to the source CSV file
set theMainFile to (path to desktop as text) & "main.csv"
tell application "System Events"
	set sourceLength to size of file theMainFile
end tell
# Define (and possibly create) the folder where new files will be stored
set p2d to (path to desktop as text)
set storage to "les Fiches"
set targetFolder to p2d & storage & ":" # Don't forget the colon!
tell application "System Events"
	if not (exists folder targetFolder) then
		make new folder at end of folder p2d with properties {name:storage}
	end if
end tell

set beg to 1
repeat # external loop
	# Read a chunk of text.
	# As is, assumes that the longer sublist descriptor is less than 10000 characters long
	set leTexte to read file theMainFile from beg for 10000
	
	# Remove the strings "START_"
	set duTexte to my supprime(leTexte, "START_")
	# Split the chunk of text using "END_" as delimiter
	set enListe to my decoupe(duTexte, "END_")
	
	set oldnameOfSublist to ""
	repeat with i from 1 to ((count enListe) - 1) # internal loop
		(*
I'm quite sure that the code used here may be enhanced but my goal 
was to build quickly a script doing the job.
It will be time for refinements if it prove to be satisfying.
*)
		set item_i to item i of enListe
		if item_i contains "," and (last paragraph of item_i does not contain ",") then
			set nameOfSublist to paragraph 1 of item_i
			if nameOfSublist is "" then set item_i to text 2 thru -1 of item_i
			if (paragraph 2 of item_i) does not contain "," then set nameOfSublist to paragraph 2 of item_i
			
			set lenOfBlock_i to (count item_i) + (count ("START_")) + (count ("END_")) + (count nameOfSublist) - (count oldnameOfSublist)
			set oldnameOfSublist to nameOfSublist
			set beg to beg + lenOfBlock_i
			if i = 1 then
				set aSublist to paragraphs 2 thru -2 of item_i
			else --  if i < (count enListe) then
				set aSublist to paragraphs 3 thru -2 of item_i
			end if
			set aSublist to my recolle(aSublist, return)
			
			set fpath to targetFolder & nameOfSublist & ".csv"
			my writeto(fpath, aSublist, text, false)
		end if
	end repeat # internal loop
	
	set beg to beg + 1
	if beg ≥ sourceLength then exit repeat
end repeat # external loop

#=====

on decoupe(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

#=====

on recolle(l, d)
	local oTIDs, t
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end recolle

#=====
(*
removes every occurences of d in text t
*)
on supprime(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to ""
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end supprime

#=====
(*
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 text
		set openFile to open for access file 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 file targetFile
		end try
		return false
	end try
end writeto

#=====

I know, some readers dislike my use of varNames built upon French words but building this kind of name is a second nature for me.

Yvan KOENIG (VALLAURIS, France) mardi 16 décembre 2014 15:02:56

Well it bothered me that you couldn’t get my code to work. It could be that you might already have the two files, “Levels.csv” and “Targets.csv” in your folder that contains the data file. I have added a routine to handle this in the following script. Tested on my machine and if these two files exist, they are deleted and the routine runs creating new files of the same names.

Best,
:slight_smile:


set csvFile to (choose file with prompt "Select CSV file..." of type {"csv"}) as text
set csvPath to my extractPath(csvFile)

set levelsFile to csvPath & "Levels.csv" as text
set targetsFile to csvPath & "Targets.csv" as text

my fileClear(levelsFile)

set csvRecords to read file csvFile using delimiter {return}

set levelsFlag to false
set targetsFlag to false

repeat with thisRecord in csvRecords
	set recordItems to my getItems(thisRecord)
	
	if item 1 of recordItems = "END_LEVELS" then
		set levelsFlag to false
		try
			close access file outputFile
		end try
	end if
	if levelsFlag then
		write thisRecord & return to outFileRef
	end if
	if item 1 of recordItems = "START_LEVELS" then
		set levelsFlag to true
		set outputFile to csvPath & "Levels.csv"
		try
			set outFileRef to open for access file outputFile with write permission
		on error
			try
				close access file outputFile
			end try
		end try
	end if
	
	if item 1 of recordItems = "END_TARGETS" then
		set targetsFlag to false
		try
			close access file outputFile
		end try
	end if
	if targetsFlag then
		write thisRecord & return to outFileRef
	end if
	if item 1 of recordItems = "START_TARGETS" then
		set targetsFlag to true
		set outputFile to csvPath & "Targets.csv"
		try
			set outFileRef to open for access file outputFile with write permission
		on error
			try
				close access file outputFile
			end try
		end try
	end if
	
end repeat

on getItems(theRecord)
	copy the text item delimiters to origDelims
	set the text item delimiters to ","
	set recordItems to {}
	set recordItems to every text item of theRecord
	set the text item delimiters to origDelims
	return recordItems
end getItems

on extractPath(theFile)
	set tid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to ":"
	set fileParts to text items of theFile
	set thePath to text items 1 thru -2 of fileParts as text
	set AppleScript's text item delimiters to tid
	set thePath to thePath & ":" as text
	return thePath
end extractPath

on fileClear(theFile)
	tell application "Finder"
		if exists theFile then
			delete file theFile
		end if
	end tell
end fileClear

Hello

As we aren’t sure that the source file uses return as line separator it would be better to replace

set csvRecords to read file csvFile using delimiter {return}

by

set csvRecords to paragraphs of ( read file csvFile )

This way, return, linefeed or even pairs return+linefeed would be correctly used as line separators.

Yvan KOENIG (VALLAURIS, France) mardi 16 décembre 2014 17:11:39

Thanks so much for the update and the follow-up from both of you!

First off, let me say that I have figured out how to get smaller already-split-up files output from my source software, so I actually no longer really need the script.

That said, I really appreciate your work, and I know how unsatisfying it is to have code that just doesn’t work as you expect it to. So I did try your newest scripts and wanted to let you know the results anyway.

haolesurferdude: I ran your most recent script but took Yvan’s suggestion about the substitution. This time, when I ran it, it ran for about 6 minutes and made a “Levels.csv” and a “Targets.csv” then it threw an error:

error “Can’t get item 1 of {}.” number -1728 from item 1 of {}

Yvan Koenig: I ran your script and it has really got my MacBook Pro cooking with the fans running on high for the last 8 minutes. I have to step away from the computer now, but I’ll leave it running. So far no new files have been created.

If you guys want to test it yourself on the real file, I’ve uploaded a sample to here: https://dl.dropboxusercontent.com/u/1378250/main.csv

Like I said at the beginning, I am actually moving forward with a different solution, so I don’t need any follow-up on this, but if you want to get it solved for the future readers of this post, go for it!

I carefully asked you for the length of subfiles.
I carefully wrote that as you didn’t answer my question, I built the script assuming that the longer subfile was less than 10000 characters.

In the passed sample file, the first sublist descriptor is 3,251,721 bytes long.
It seems that you didn’t read my comments.

Edit the lines :

	# As is, assumes that the longer sublist descriptor is less than 10000 characters long
	set leTexte to read file theMainFile from beg for 10000

to

	# As is, assumes that the longer sublist descriptor is less than 4000000 characters long
	set leTexte to read file theMainFile from beg for 4000000

and the job will be done in a few seconds.

Your sublists are so long that one of them is breaking the row limit of Numbers.

Yvan KOENIG (VALLAURIS, France) mardi 16 décembre 2014 19:25:31

Thanks Yvan!!!

Merci beaucoup! (The best of what’s left of my French… My family moved from Bordeaux when I was seven.)

I always get great things from your wonderful work.

Sincerely,
:slight_smile:

Indeed! Thanks, Yvan. Sorry about not understanding and answering your questions about the length of the file.
Still, so glad to have found this forum. I’ll be sure to come back with any future AppleScript needs. :slight_smile:

Let’s keep it simple, assuming TARGETS comes after LEVELS:

set ti to current date

set f to "/Users/xpto/Desktop/main.text"
set fl to "/Users/xpto/Desktop/Levels.csv"
set ft to "/Users/xpto/Desktop/Targets.csv"


set f to open for access f
set t to read f
close access f


set fi to (offset of "Start_LEVELS\n" in t) + (count of "Start_LEVELS\n")
set fe to (offset of "END_LEVELS" in t) - 1

set fl to open for access fl with write permission
set eof fl to 0
write (text fi thru fe of t) to fl
close access fl
set t to text (fe + 1) thru -1 of t

set ft to open for access ft with write permission
set eof ft to 0
set fi to (offset of "START_TARGETS\n" in t) + (count of "START_TARGETS\n")

set fe to (offset of "END_TARGETS" in t) - 1
write (text fi thru fe of t) to ft
close access ft

log (current date) - ti

– started
(71)
– stopped

It still took a bit more than 1 minute. But hey, in an eMAc.

CAUTION, the sample main.csv file contain more than two lists bringing normally these files :

LEVELS.csv with 66528 lines
TARGETS.csv with 1044 lines
CHANNELS.csv with 199 lines
FIXTURES.csv with 60 lines
SHOWCONTROL.csv which is in fact just a line of titles

Yvan KOENIG (VALLAURIS, France) mercredi 17 décembre 2014 18:20:29

Hello folks! I’m back. This solution has been working well for me ever since you helped me arrive at it back in December 2014. But now, I’ve come across a new file that is giving the script problems.

To review, here is my current script:

# Define the path to the source CSV file
set theMainFile to (choose file with prompt "Select EOS CSV file..." of type {"csv"}) as text

tell application "System Events"
	set sourceLength to size of file theMainFile
end tell
# Define (and possibly create) the folder where new files will be stored
set p2f to "Mandela:Users:Jake:JDLD:01-Projects:UPH Local:04-HiLight:" as text
set storage to "Import"
set targetFolder to p2f & storage & ":" # Don't forget the colon!
tell application "System Events"
	if not (exists folder targetFolder) then
		make new folder at end of folder p2f with properties {name:storage}
	end if
end tell

set beg to 1
repeat # external loop
	# Read a chunk of text.
	# As is, assumes that the longer sublist descriptor is less than 100,000,000 characters long
	tell application "Finder"
		set leTexte to read file theMainFile from beg for 1.0E+10
	end tell
	
	# Remove the strings "START_"
	set duTexte to my supprime(leTexte, "START_")
	# Split the chunk of text using "END_" as delimiter
	set enListe to my decoupe(duTexte, "END_")
	
	set oldnameOfSublist to ""
	repeat with i from 1 to ((count enListe) - 1) # internal loop
		(* I'm quite sure that the code used here may be enhanced but my goal  was to build quickly a script doing the job. It will be time for refinements if it prove to be satisfying. *)
		set item_i to item i of enListe
		if item_i contains "," and (last paragraph of item_i does not contain ",") then
			set nameOfSublist to paragraph 1 of item_i
			if nameOfSublist is "" then set item_i to text 2 thru -1 of item_i
			if (paragraph 2 of item_i) does not contain "," then set nameOfSublist to paragraph 2 of item_i
			
			set lenOfBlock_i to (count item_i) + (count ("START_")) + (count ("END_")) + (count nameOfSublist) - (count oldnameOfSublist)
			set oldnameOfSublist to nameOfSublist
			set beg to beg + lenOfBlock_i
			if i = 1 then
				set aSublist to paragraphs 2 thru -2 of item_i
			else --  if i < (count enListe) then
				set aSublist to paragraphs 3 thru -2 of item_i
			end if
			set aSublist to my recolle(aSublist, return)
			
			set fpath to targetFolder & nameOfSublist & ".csv"
			my writeto(fpath, aSublist, text, false)
		end if
	end repeat # internal loop
	
	set beg to beg + 1
	if beg ≥ sourceLength then exit repeat
end repeat # external loop

#=====

on decoupe(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

#=====

on recolle(l, d)
	local oTIDs, t
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end recolle

#=====
(* removes every occurences of d in text t *)
on supprime(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to ""
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end supprime

#=====
(* 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 text
		set openFile to open for access file targetFile with write permission
		if not apendData then set eof of openFile to 0
		tell application "Finder"
			write theData to openFile starting at eof as dataType
		end tell
		close access openFile
		return true
	on error
		try
			close access file targetFile
		end try
		return false
	end try
end writeto

#=====

Here’s the .csv I am trying to split: https://www.dropbox.com/s/tqpz3kncn57x75z/Up%20Here.csv?dl=0

There seems to be to problems. First, there are lines of content in the file which include the string “END_” which is the same as the string that we are using to find the end of a sublist. I don’t see any way around this except to manually remove the occurrences from the file. I did that step to create this version of the file: https://www.dropbox.com/s/xebf995qvcu7rgf/Up%20Here%20NoEND.csv?dl=0

But this one is once again running very slowly with the script. It runs so quickly on other files. What is the problem with this one? Is it just the length of the LEVELS table (14 million characters over 288k lines)? Is there any way to speed the script up on such a long file?

(1) Its always boring to see that helped persons feel free to add instructions when they don’t understand what they are doing.

I never encapsulated a read instruction (read belongs to Standard Additions) in a tell Finder block.
Why did you added these odd instructions ?

(2) The main problem here was that the source file contains delimiters starting with “START_” or “END_” and standard content contain strings “end_”
The way to solve it was to edit the “decoupe” handler so that it makes the difference between the different strings.
Happily it’s easy because AppleScript give us the control statement “considering case” (and its counterpart “end considering”)

Inserting them in the handler solved the problem.

Here is the modified script and PLEASE DON’T RE-ENABLE YOUR ODD INSTRUCTIONS SPEAKING TO FINDER !
If you post again about this script, If I see these odd instructions enabled I will not respond.

# Define the path to the source CSV file
set theMainFile to (choose file with prompt "Select EOS CSV file..." of type {"csv"}) as text
--set theMainfile to (path to home folder as text)&"Downloads:Up Here.csv"
tell application "System Events"
	set sourceLength to size of file theMainFile
end tell
# Define (and possibly create) the folder where new files will be stored
set p2f to "Mandela:Users:Jake:JDLD:01-Projects:UPH Local:04-HiLight:" as text
--set p2f to path to desktop as text
set storage to "Import"
set targetFolder to p2f & storage & ":" # Don't forget the colon!
tell application "System Events"
	if not (exists folder targetFolder) then
		make new folder at end of folder p2f with properties {name:storage}
	end if
end tell

set beg to 1
repeat # external loop
	# Read a chunk of text.
	# As is, assumes that the longer sublist descriptor is less than 100,000,000 characters long
	--tell application "Finder" # I NEVER ENCAPSULATED READ IN A TELL FINDER BLOCK !
	set leTexte to read file theMainFile from beg for 100000000
	--end tell # I NEVER ENCAPSULATED READ IN A TELL FINDER BLOCK !
	
	# Remove the strings "START_"
	set duTexte to my supprime(leTexte, "START_")
	# Split the chunk of text using "END_" as delimiter
	set enListe to my decoupe(duTexte, "END_")
	
	set oldnameOfSublist to ""
	repeat with i from 1 to ((count enListe) - 1) # internal loop
		(* I'm quite sure that the code used here may be enhanced but my goal  was to build quickly a script doing the job. It will be time for refinements if it prove to be satisfying. *)
		set item_i to item i of enListe
		if item_i contains "," and (last paragraph of item_i does not contain ",") then
			set nameOfSublist to paragraph 1 of item_i
			if nameOfSublist is "" then set item_i to text 2 thru -1 of item_i
			if (paragraph 2 of item_i) does not contain "," then set nameOfSublist to paragraph 2 of item_i
			
			set lenOfBlock_i to (count item_i) + (count ("START_")) + (count ("END_")) + (count nameOfSublist) - (count oldnameOfSublist)
			set oldnameOfSublist to nameOfSublist
			set beg to beg + lenOfBlock_i
			if i = 1 then
				set aSublist to paragraphs 2 thru -2 of item_i
			else --  if i < (count enListe) then
				set aSublist to paragraphs 3 thru -2 of item_i
			end if
			set aSublist to my recolle(aSublist, return)
			
			set fpath to targetFolder & nameOfSublist & ".csv"
			my writeto(fpath, aSublist, text, false)
		end if
	end repeat # internal loop
	
	set beg to beg + 1
	if beg ≥ sourceLength then exit repeat
end repeat # external loop

#=====

on decoupe(t, d)
	local oTIDs, l
	considering case # ADDED So that it split upon START_ or END_ but not upon start_ or end_
		set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
		set l to text items of t
		set AppleScript's text item delimiters to oTIDs
	end considering # Restore the standard behavior
	return l
end decoupe

#=====

on recolle(l, d)
	local oTIDs, t
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end recolle

#=====
(* removes every occurences of d in text t *)
on supprime(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to ""
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end supprime

#=====
(* 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
		tell application "Finder"
			write theData to openFile starting at eof as dataType
		end tell
		close access openFile
		return true
	on error
		try
			close access targetFile
		end try
		return false
	end try
end writeto

#=====

Yvan KOENIG (VALLAURIS, France) mercredi 15 juillet 2015 12:39:20

When you have the scripting addition AppleScript Toolbox installed and the files are UTF8 encoded (of not using extended 8 byte characters) you can simplify your script to this:

-- Thanks for Yvan pointing to the fact that handler calls have to be addressed 
-- explicitly to the root script object (my/me). 
my saveSubRows("START_LEVELS", "END_LEVELS", "/path/to/source.csv", "/path/to/level.csv", linefeed)
my saveSubRows("START_TARGETS", "END_TARGETS", "/path/to/source.csv", "/path/to/target.csv", linefeed)

on saveSubRows(startTag, endTag, sourceFile, targetFile, rowDelimiter)
	set csvData to AST find regex ("" & startTag & rowDelimiter & "(.*)" & rowDelimiter & endTag) in file sourceFile regex group 2 with case sensitivity
	
	try
		set fd to open for access targetFile with write permission
		set eof of fd to 0
		write csvData to fd as «class utf8»
		close access fd
	on error
		close access targetFile
	end try
end saveSubRows

Merci, Yvan!

Thank you for not giving up on me.

The reason I added those instructions is because I am generating this script dynamically in FileMaker Pro and without them, I couldn’t get it to work. When I run it via AppleScript editor it works, but when I have FileMaker run it, it doesn’t. So this was my workaround rather than continuing to bother you. But I bet there’s a much better way that that…

Your revised script is brilliant in the way it looks at case. Thank you!

It is still running very slowly on my new sample file. Is that just the nature of working with such a long CSV? Any way to speed it up?