splitting up a string

  • (2 Pages)
  • +
  • 1
  • 2

20 Replies - 3551 Views - Last Post: 31 January 2013 - 09:41 PM

#1 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

splitting up a string

Posted 29 January 2013 - 03:19 PM

I am very lost on this one...

problem:

I need to convert a string to lists of characters, split them based on delimiters, and convert back. I also need locally defined functions

the function call would look like
(split string-here delimiters)
(split "Blah, Blah blah!" " ,!")
the function should return ("Blah" "" "Blah" "blah" "")


Being that I'm having trouble with practically every aspect of this function, I figure I can start from the top and hopefully by the end I will have everything figured out. First, Ill start with trying to iterate through a string, converting each character into a list. I actually have something thats somewhat close here, but youll see why its not right.

(defun toList (str number)
;(toList(cons(char str (+ number 1))(char str (+ number 2)))))

(if (or (null str) (= number (length str))) nil (cons(char str number)(toList str (+ 1 number)) ))
);end



[52]> (toList "hello" 0)
(#\h #\e #\l #\l #\o)

how do I get rid of the #\




next, i'll try and make this a locally defined function

(defun split (str delim)

(labels toList (str number)


(if (or (null str) (= number (length str))) nil (cons(char str number)(toList str (+ 1 number)) ))
);end



);end



Is This A Good Question/Topic? 0
  • +

Replies To: splitting up a string

#2 Tayacan  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 145
  • View blog
  • Posts: 275
  • Joined: 18-January 11

Re: splitting up a string

Posted 29 January 2013 - 03:47 PM

I believe the #\ is just Lisps way of saying "this is a char". Like, if it was just (h e l l o), how would you know if h was a char or an atom?
Was This Post Helpful? 3
  • +
  • -

#3 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 29 January 2013 - 04:25 PM

View PostTayacan, on 29 January 2013 - 03:47 PM, said:

I believe the #\ is just Lisps way of saying "this is a char". Like, if it was just (h e l l o), how would you know if h was a char or an atom?


Yup I figured that out lol. I also figured out how to turn something into a local function, but the website wasnt loading properly for me to update. However, I still have other issues with this function that need to be addressed. So, if someone could help me with the following:
EDIT: I got this part look at the next post :)

the idea behind the code after this is that it will take a string, and a string of delimiters and a number (starting point, usually 0)
it will check to see if str matches any character in delim, if it does, return true.


(defun dCheck (str delim number)
;Check if the character is a delimiter 
//;(if condition then-part else-part)

(if (or (null str) (null delim)) nil  (if (char= (str)(char delim (+ number 1))) t dCheck(str delim (+ 1 number)) ) )

);end




error:

*** - EVAL: too many parameters for special operator IF: (IF (CHAR= (STR) (CHAR DELIM (+ NUMBER 1))) T DCHECK (STR DELIM (+ 1 NUMBER)))
The following restarts are available:

This post has been edited by NecroWinter: 29 January 2013 - 04:45 PM

Was This Post Helpful? 0
  • +
  • -

#4 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 29 January 2013 - 04:50 PM

okay so, I got that part.

This is what it looks like

(defun dCheck (str delim number)
;Check if the character is a delimiter 
//;(if condition then-part else-part)

(if (or(or (null str) (null delim))(= number (length delim))) nil 


(if (char= (char str 0) (char delim number)) t (dCheck str delim (+ number 1)));end char= if

);end main if

);end






anyway, it seems right.

Now I need to piece it all together so that I can split up a string based on delimiters.

Heres my current code:
(defun split (str delim)

;toLIST FUNCTION
(labels ((toList (str number)
;Convert a string to a list

(if (or (null str) (= number (length str))) nil (cons(subseq str number (+ number 1))(toList str (+ 1 number)) ))
)));end

;dCHECK FUNCTION
(labels ((dCheck (str delim number)
;Check if the character is a delimiter 


(if (or(or (null str) (null delim))(= number (length delim))) nil 


(if (char= (char str 0) (char delim number)) t (dCheck str delim (+ number 1)));end char= if

);end main if

)));end




);end


a question I ask is, should I use a for loop here (check each part of the list)? How do I piece this all together as planned in the original post?

Im gonna keep working on it, hopefully someone gives me some tips in the mean time

This post has been edited by NecroWinter: 29 January 2013 - 04:51 PM

Was This Post Helpful? 0
  • +
  • -

#5 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 29 January 2013 - 05:21 PM

(defun split (str delim)
;;;;;;;;;;;;;;;LOCAL FUNCTIONS
;toLIST FUNCTION
(labels ((toList (str number)
;Convert a string to a list

(if (or (null str) (= number (length str))) nil (cons(subseq str number (+ number 1))(toList str (+ 1 number)) ))
)));end

;dCHECK FUNCTION
(labels ((dCheck (str delim number)
;Check if the character is a delimiter 


(if (or(or (null str) (null delim))(= number (length delim))) nil 


(if (char= (char str 0) (char delim number)) t (dCheck str delim (+ number 1)));end char= if

);end main if

)));end


;;;;;;;;; end local functions

;loop through the list from STR, checking if there are delimiters
(loop for i in (toList str 0) do 


(dCheck (string i) delim 0)


);end for

);end



toList converts a string to a list of characters
dCheck checks each character to see if its a delimiter

Im attempting a for loop to go through and rebuild a string from a list, but can you even do that? Ive only ever done it with recursion, and recursion doesnt seem like it makes sense in this context, you dont want to constantly redefine local functions and redo all the other work being doing in this
Was This Post Helpful? 0
  • +
  • -

#6 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 29 January 2013 - 06:54 PM

read the previous post to help clarify the code here

(defun split (str delim)
;;;;;;;;;;;;;;;LOCAL FUNCTIONS
;toLIST FUNCTION
(labels ((toList (str number)
;Convert a string to a list

(if (or (null str) (= number (length str))) nil (cons(subseq str number (+ number 1))(toList str (+ 1 number)) ))
)));end

;dCHECK FUNCTION
(labels ((dCheck (str delim number)
;Check if the character is a delimiter 


(if (or(or (null str) (null delim))(= number (length delim))) nil 


(if (char= (char str 0) (char delim number)) t (dCheck str delim (+ number 1)));end char=if

);end mainif

)));end


;;;;;;;;; end local functions

;loop through the list from STR, checking if there are delimiters

(setq theList nil)
(setq tmp nil)
(loop for i in (toList str 0) do 


(if (not (dCheck (string i) delim 0))

;then
(append tmp i)
;else
(
(append theList (concatenate 'string tmp))
(setq tmp nil)
)
)


);end for

(return-from split theList)
);end


im getting the error:
*** - SYSTEM::%EXPAND-FORM: (APPEND THELIST (CONCATENATE 'STRING TMP)) should be a lambda expression


I hope someone can help me with this, Im really at a loss here. the problem begins where the for loop starts

This post has been edited by NecroWinter: 29 January 2013 - 07:02 PM

Was This Post Helpful? 0
  • +
  • -

#7 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2009
  • View blog
  • Posts: 3,031
  • Joined: 21-June 11

Re: splitting up a string

Posted 29 January 2013 - 07:47 PM

First of all, you should really indent your code properly and don't write too much on one line - the then- and else-parts of an if should be each on its own line. This makes errors like "too many arguments for if" much easier to detect.

Take a look at this: Indenting Common Lisp.

View PostNecroWinter, on 30 January 2013 - 01:21 AM, said:

;loop through the list from STR, checking if there are delimiters
(loop for i in (toList str 0) do 


(dCheck (string i) delim 0)


);end for


That won't work. Your code above is equivalent to this in an imperative language:

for(i in toList(str, 0)) {
    dCheck(string(i), delim, 0);
}



where dCheck is a boolean function with no side-effects. Consequently it will simply not do anything. Generally you should only use loop ... do with a body that causes side-effects (like if you're printing the values inside the body).

Quote

Im attempting a for loop to go through and rebuild a string from a list, but can you even do that?


You shouldn't be using loop ... do. The only way to produce values using loop ... do would be by using side-effecting functions like setf/setq and that's not very lispy. If you use loop, you should be using loop ... collecting or loop ... appending or something like that. However if you haven't covered loop yet, you probably shouldn't be using loop at all.

Quote

Ive only ever done it with recursion, and recursion doesnt seem like it makes sense in this context, you dont want to constantly redefine local functions and redo all the other work being doing in this


Right, that's why, in cases like this, it often makes sense to define a local function that's recursive. So if the local function recurses, the definitions of the outer function don't get redefined.

This post has been edited by sepp2k: 29 January 2013 - 07:43 PM

Was This Post Helpful? 2
  • +
  • -

#8 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 29 January 2013 - 07:56 PM

View Postsepp2k, on 29 January 2013 - 07:47 PM, said:

First of all, you should really indent your code properly and don't write too much on one line - the then- and else-parts of an if should be each on its own line. This makes errors like "too many arguments for if" much easier to detect.

Take a look at this: Indenting Common Lisp.

View PostNecroWinter, on 30 January 2013 - 01:21 AM, said:

;loop through the list from STR, checking if there are delimiters
(loop for i in (toList str 0) do 


(dCheck (string i) delim 0)


);end for


That won't work. Your code above is equivalent to this in an imperative language:

for(i in toList(str, 0)) {
    dCheck(string(i), delim, 0);
}



where dCheck is a boolean function with no side-effects. Consequently it will simply not do anything. Generally you should only use loop ... do with a body that causes side-effects (like if you're printing the values inside the body).

Quote

Im attempting a for loop to go through and rebuild a string from a list, but can you even do that?


You shouldn't be using loop ... do. The only way to produce values using loop ... do would be by using side-effecting functions like setf/setq and that's not very lispy. If you use loop, you should be using loop ... collecting or loop ... appending or something like that. However if you haven't covered loop yet, you probably shouldn't be using loop at all.

Quote

Ive only ever done it with recursion, and recursion doesnt seem like it makes sense in this context, you dont want to constantly redefine local functions and redo all the other work being doing in this


Right, that's why, in cases like this, it often makes sense to define a local function that's recursive. So if the local function recurses, the definitions of the outer function don't get redefined.

Thats definitely something I noticed... that the way I was going about this wasn't very "lispy", but unfortunately, my experience with Lisp is very limited (which also explains why my indentation is so bad, I will look at that link)

So, overall, what do you think my strategy should actually be to complete this function? Should I write additional local functions, perhaps one to replace the loop(but recursive)? I ask, because it seems very easy to get away from the way Lisp is meant to work if you're not used to functional programming.
Was This Post Helpful? 0
  • +
  • -

#9 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2009
  • View blog
  • Posts: 3,031
  • Joined: 21-June 11

Re: splitting up a string

Posted 29 January 2013 - 08:08 PM

View PostNecroWinter, on 30 January 2013 - 02:54 AM, said:

[code]
(loop for i in (toList str 0) do
(if (not (dCheck (string i) delim 0))
;then
(append tmp i)
;else
(
(append theList (concatenate 'string tmp))
(setq tmp nil)
)
)


First of all you might be misunderstanding how append works. Bboth arguments to append should be lists. And even more importantly: (append list1 list2) returns a list that contains both the elements of list1 and list2. It does not change the contents of list1. So if you call append and don't do anything with its result, you're doing it wrong.

Secondly,

Quote

im getting the error:
*** - SYSTEM::%EXPAND-FORM: (APPEND THELIST (CONCATENATE 'STRING TMP)) should be a lambda expression


That's because you wrote ( (append ...) (setq ...) ). In Lisp parentheses surround function or macro calls. So in the above Lisp thinks that (append ...) is the function you're trying to call and (setq ...) is the argument you're trying to call it with. That is it thinks that (append ...) will return a lambda (anonymous function).

If you want to evaluate multiple side-effecting functions after each other, you should use (progn (append ...) (setq ...)), but as I already said, append isn't a side-effecting function, so that won't do what you want either (it will get rid of the error though). Generally you should avoid progn.
Was This Post Helpful? 2
  • +
  • -

#10 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2009
  • View blog
  • Posts: 3,031
  • Joined: 21-June 11

Re: splitting up a string

Posted 29 January 2013 - 08:16 PM

View PostNecroWinter, on 30 January 2013 - 03:56 AM, said:

So, overall, what do you think my strategy should actually be to complete this function? Should I write additional local functions, perhaps one to replace the loop(but recursive)? I ask, because it seems very easy to get away from the way Lisp is meant to work if you're not used to functional programming.


I think the easiest solution here would be a recursive function. There's nothing unlispy about using loop¹ (as long as you don't use loop ... do + set functions), but to do what you want here, the loop would probably get a bit complicated and you don't seem to be all that familiar with the loop construct yet.

¹ As far as I am concerned, anyway. Some people argue that loop is unlispy by nature because it has a lot of English keywords and not a lot of parens (or something like that).

This post has been edited by sepp2k: 29 January 2013 - 08:18 PM

Was This Post Helpful? 2
  • +
  • -

#11 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 30 January 2013 - 05:09 PM

Ok, so luckily my professor pushed back the due date, and I'm actually making a lot of progress! One small issue though, I have a function that takes two lists of characters (one is from a string that contains a phrase or a word, the other is a list of delimiters)

Im also trying to make my code more readable, but I have not had time to read the link sepp gave me on formatting code.

So take a look at my code at the bottom, the function dC does most of the work, the function toList seems like its correct, and its formatted poorly, so feel free to not even look at it.

so if I try this function, this is the expected result:
(split "To iterate is human, to recurse divine!" " ,!")
result: ("To" "iterate" "is" "human" "" "to" "recurse" "divine" "")

this is what I get: ("To" "iterate" "is" "human" NIL "to" "recurse" "divine")

In my code I replaced the nil return instruction with "" but it causes really strange errors, and its very clearly not correct.

(defun split (str delim)
;;;;;;;;;;;;;;;LOCAL FUNCTIONS
;toLIST FUNCTION
(labels ((toList (str number)
;Convert a string to a list

(if (or (null str) (= number (length str))) nil (cons(subseq str number (+ number 1))(toList str (+ 1 number)) ))
)));end

;dC Function
(labels ((dC(l1 delim str)

(if (or (null l1) (null delim)) nil 
  (if (member (car l1) delim) 
    (cons str (dC (cdr l1) delim nil))  
   (dC (cdr l1) delim (concatenate 'string str (string (car l1)))))

) 
)
)
);end of dC


;;;;;;;;; end local functions

(dc (tolist str 0) (tolist delim  0 ) nil)
);end

This post has been edited by NecroWinter: 30 January 2013 - 05:10 PM

Was This Post Helpful? 0
  • +
  • -

#12 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2009
  • View blog
  • Posts: 3,031
  • Joined: 21-June 11

Re: splitting up a string

Posted 30 January 2013 - 08:14 PM

View PostNecroWinter, on 31 January 2013 - 01:09 AM, said:

In my code I replaced the nil return instruction with "" but it causes really strange errors, and its very clearly not correct.


What exactly do you mean by the "nil return instruction"? In your code there are two places where you call dC with nil as the third argument. I think if you replace those nils with "", it will work. If that's what you meant that causes the strange errors, please elaborate what those errors are.
Was This Post Helpful? 1
  • +
  • -

#13 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 30 January 2013 - 10:22 PM

View Postsepp2k, on 30 January 2013 - 08:14 PM, said:

View PostNecroWinter, on 31 January 2013 - 01:09 AM, said:

In my code I replaced the nil return instruction with "" but it causes really strange errors, and its very clearly not correct.


What exactly do you mean by the "nil return instruction"? In your code there are two places where you call dC with nil as the third argument. I think if you replace those nils with "", it will work. If that's what you meant that causes the strange errors, please elaborate what those errors are.


The strange errors that I spoke of came from the fact that I had "dc" previously defined in my clisp session, it was running old code. Turns out, the code I have presented has a syntax error and DC is not getting defined correctly anyway. I am trying to figure out what I did wrong but I would appreciate someone stepping in and pointing out where my syntax is wrong

by nil return instruction I meant the very first nil you see in DC, but I want to get the syntax correct for labels first

This post has been edited by NecroWinter: 30 January 2013 - 10:23 PM

Was This Post Helpful? 0
  • +
  • -

#14 NecroWinter  Icon User is offline

  • D.I.C Regular

Reputation: 35
  • View blog
  • Posts: 315
  • Joined: 21-October 11

Re: splitting up a string

Posted 30 January 2013 - 11:39 PM

So basically whats happening is that im creating a local function and then not using it because its closed off. The only reason I thought my code worked is because I am in a clisp session testing code, and my functions were previously defined. If I can get them locally declared correctly, im sure the code will work.

So heres a straight forward question, what is the syntax to define two local functions? I cant find this online anywhere, but im sure you can do it. Every example I find online is meant for one local function
Was This Post Helpful? 0
  • +
  • -

#15 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2009
  • View blog
  • Posts: 3,031
  • Joined: 21-June 11

Re: splitting up a string

Posted 31 January 2013 - 12:07 AM

(labels
  ( (function-1 (a B)/>/>
      body-of-function-1)
    (function-2 (x y)
      body-of-function-2))
  code-that-uses-functions-1-and-2))


Basically it's the exact same syntax as let except that it defines functions instead of variables.

You can also use nested defuns, which would be closer to the syntax you were trying to use:

(defun outer-function (params)
  (defun inner-function-1 (params)
    body-of-inner-function-1)
  (defun inner-function-2 (params)
    body-of-inner-function-2)

  code-that-uses-the-inner-functions)


This post has been edited by sepp2k: 31 January 2013 - 12:08 AM

Was This Post Helpful? 2
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2