 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
lrh9
Joined: 10 Jun 2009 Posts: 102
|
Posted: Wed Jun 17, 2009 5:27 pm Post subject: [SOLVED] StringSplit to divide an incoming string using... |
|
|
spaces as delimiters except when quotes are encountered.
For example:
incoming_string = she sells sea shells "by the sea shore"
After running through string split I would like to produce the following array:
out_array[0] = she
out_array[1] = sells
out_array[2] = sea
out_array[4] = shells
out_array[5] = by the sea shore
Is it possible to get StringSplit to behave like that? Or to accomplish that using some other command?
Last edited by lrh9 on Tue Sep 01, 2009 9:57 am; edited 1 time in total |
|
| Back to top |
|
 |
lrh9
Joined: 10 Jun 2009 Posts: 102
|
Posted: Wed Jun 17, 2009 5:34 pm Post subject: |
|
|
| I looked at loop parsing for strings. It appears that both of them aren't up to the task. I think I'm going to have to write a custom function to be able to do what I described. |
|
| Back to top |
|
 |
Frankie
Joined: 02 Nov 2008 Posts: 2850
|
Posted: Wed Jun 17, 2009 6:06 pm Post subject: |
|
|
| Code: | split("she sells sea shells ""by the sea shore""", "output_array")
Loop 5
Msgbox % output_array%A_Index%
ExitApp
Return
split(String, output_array) {
global
StringSplit, String, String, "
StringSplit, %output_array%, String1, %A_Space%
Pos := %output_array%0
%output_array%%Pos% := String2
Return
} | There has to be a better way to do this but it works. _________________ aboutscript ⍟ apps ⍟ scripts
Any code ⇈ above ⇈ requires AutoHotkey_L to run |
|
| Back to top |
|
 |
MasterFocus
Joined: 08 Apr 2009 Posts: 3035 Location: Rio de Janeiro - RJ - Brasil
|
Posted: Wed Jun 17, 2009 6:24 pm Post subject: |
|
|
| Frankie wrote: | | Code: | split("she sells sea shells ""by the sea shore""", "output_array")
Loop 5
Msgbox % output_array%A_Index%
ExitApp
Return
split(String, output_array) {
global
StringSplit, String, String, "
StringSplit, %output_array%, String1, %A_Space%
Pos := %output_array%0
%output_array%%Pos% := String2
Return
} |
|
I suggest not using "global".
| Code: | split("she sells sea shells ""by the sea shore""", "outArray")
Loop 5
Msgbox % outArray%A_Index%
ExitApp
Return
split(String, output_array) {
local Pos, String1, String2
StringSplit, String, String, "
StringSplit, %output_array%, String1, %A_Space%
Pos := %output_array%0
%output_array%%Pos% := String2
Return
} |
_________________ "Read the manual. Read it again. Search the forum.
Try something before asking. Show what you've tried."
Antonio França
My stuff: Google Profile |
|
| Back to top |
|
 |
jaco0646
Joined: 07 Oct 2006 Posts: 3113 Location: MN, USA
|
Posted: Wed Jun 17, 2009 7:56 pm Post subject: |
|
|
Here's a way to do it with a loop (creates a global array; array0 contains the number of elements). | Code: | string = she sells sea shells "by the sea shore"
Loop, Parse, string, %A_Space%
{
If quote {
array%i% .= A_Space A_LoopField
If InStr(A_LoopField,"""")
quote = 0
continue
}
i++
array0 := i
array%i% := A_LoopField
If InStr(A_LoopField,"""")
quote = 1
}
Loop,% array0
list .= "array" A_Index " = " array%A_Index% "`n"
MsgBox, %list% |
EDIT: here's the same thing, wrapped in a function. | Code: | string = she sells sea shells "by the sea shore"
QSplit(string)
Loop,% array0
list .= "array" A_Index " = " array%A_Index% "`n"
MsgBox, %list%
return
QSplit(string) {
local quote, i
Loop, Parse, string, %A_Space%
{
If quote {
array%i% .= A_Space A_LoopField
If InStr(A_LoopField,"""")
quote = 0
continue
}
i++
array0 := i
array%i% := A_LoopField
If InStr(A_LoopField,"""")
quote = 1
}
} |
|
|
| Back to top |
|
 |
lrh9
Joined: 10 Jun 2009 Posts: 102
|
Posted: Thu Jun 18, 2009 5:18 pm Post subject: |
|
|
| Is there a built in variable containing the escape character for the script/autohotkey? |
|
| Back to top |
|
 |
jaco0646
Joined: 07 Oct 2006 Posts: 3113 Location: MN, USA
|
|
| Back to top |
|
 |
lrh9
Joined: 10 Jun 2009 Posts: 102
|
Posted: Mon Jun 22, 2009 2:44 am Post subject: |
|
|
The above code looks good, but my main problem with it is that I think they would all break the string at a quote if it appeared between the delimiting quotes.
For instance, they would break up:
she sells sea shells "by the "sea" shore"
into:
1: she
2: sells
3: sea
4: shells
5: by the
6: sea
7: shore
Is there a way around it? I did something like this in c++, but I'm new to autohotkey. The way I did it in c++ was to have the substrings created by having them wrapped in single quotes and then requiring strings quoted inside to be wrapped in an escape sequence. In c++ it would look something like this:
she sells sea shells "by the \"sea\" shore"
So in autohotkey it would look like:
she sells sea shells "by the `"sea`" shore"
And they would both display as:
1: she
2: sells
3: sea
4: shells
5: by the "sea" shore
Sorry for being so picky, but I really think this is what I need. |
|
| Back to top |
|
 |
lrh9
Joined: 10 Jun 2009 Posts: 102
|
Posted: Mon Jun 22, 2009 3:26 am Post subject: |
|
|
I think I defined the necessary algorithm in pseudo-code:
Note: A single quote here is defined as a quote (`") in the string not preceded by an accent (``). This would need to be coded to. (Probably by finding each quote and then check the character immediately before it.)
While there is text in the string.
1) Search the string for a single quote. Assign the portion before the quote (or the entire string if there is not one) to a temporary variable and stringsplit that to an output array variable using the space character as the delimiter. Remove the string stored in the temporary variable from the original string. (If there was no quote, all text should have been stored in the temporary variable and then removed from the original string, meaning the loop would break.)
2) Search the string for another single quote. If one is encountered, append it to the output array variable. If not, there are two options. Treat the rest of the string as if it had a single quote at the end. (Meaning the rest of the string would be one substring.) OR discard the first quote and split the remaining text using spaces. This behavior should be user defined. I'd probably go with the first option as a default. Remove the portion of the string that was parsed from the string.
3) This will repeat until nothing remains in the string.
Example input and output:
Input = she sells sea shells "by the `"sea`" shore"
(Scan process)
Tempvar = she sells sea shells
stringsplit output tempvar " "
Output1 = she
Output2 = sells
Output3 = sea
Output4 = shells
Input = "by the `"sea`" shore"
(Scan process)
Tempvar = by the "sea" shore
Output5 = by the "sea" shore
Input =
Return |
|
| Back to top |
|
 |
jaco0646
Joined: 07 Oct 2006 Posts: 3113 Location: MN, USA
|
Posted: Mon Jun 22, 2009 3:52 am Post subject: |
|
|
A minor addition to my original code might be acceptable. | Code: | strings =
(
she sells sea shells by the sea shore
she sells sea shells by the "sea" shore
she sells sea shells "by the sea shore"
she sells sea shells "by the "sea" shore"
she sells sea shells "by "the sea" shore"
)
Loop, Parse, strings, `n, `r
MsgBox,% QSplit(A_LoopField)
return
QSplit(string) {
local quote, list, i
Loop, Parse, string, %A_Space%
{
If !quote {
i++
array0 := i
array%i% := A_LoopField
}
Else array%i% .= A_Space A_LoopField
If InStr(A_LoopField,"""") = 1
quote++
If (InStr(A_LoopField,"""","",0) = StrLen(A_LoopField))
quote--
}
Loop,% array0
list .= "array" A_Index " = " array%A_Index% "`n"
Return, list
} |
Edit1: updated code.
Edit2: updated code again.
Edit3: shortened code.
Last edited by jaco0646 on Mon Jun 22, 2009 5:09 pm; edited 2 times in total |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Mon Jun 22, 2009 8:58 am Post subject: |
|
|
| Code: | String = she sells sea shells "by the "sea" shore"
MsgBox, % DelimitParameters( String, "`n" )
DelimitParameters( CommandLine,D="|" ) { ; Supplementary function for GetCommandLine()
tempVar := CommandLine ; www.autohotkey.com/forum/viewtopic.php?p=232199#232199
Loop {
StringReplace,tempVar,tempVar,%Param%
CommandLine := DllCall( "shlwapi\PathGetArgsA", Str,CommandLine,Str )
StringReplace,Param,tempVar,%CommandLine%
DllCall( "shlwapi\PathUnquoteSpacesA", Str,Param )
IfEqual,Param,,Return SubStr(DelimitedString,2)
DelimitedString = %DelimitedString%%D%%Param%
}} |
_________________ URLGet - Internet Explorer based Downloader |
|
| Back to top |
|
 |
jaco0646
Joined: 07 Oct 2006 Posts: 3113 Location: MN, USA
|
Posted: Mon Jun 22, 2009 2:45 pm Post subject: |
|
|
I had to update my above code again; it didn't work with all combinations of quotations, so I've added some different strings to be checked. Note that my function fails if a string contains a quote between two spaces ( " ) since spaces are used as delimiters. SKAN's function won't handle it either.
@ SKAN
Your function also fails for me on multi-word nested quotes (the last example string in my above code). |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Mon Jun 22, 2009 3:23 pm Post subject: |
|
|
| jaco0646 wrote: | @ SKAN
Your function also fails for me on multi-word nested quotes (the last example string in my above code). |
My function tries to reproduce the results one would get by passing the string as a parameter to the following AHK script:
| Code: | Loop %0%
P .= %A_Index% "`n"
MsgBox, % P |
I presumed lrh9's incoming_string was actually command-line parameters.. if not, my code would not be of much use, I guess.
Thanks for testing my code.  |
|
| Back to top |
|
 |
lrh9
Joined: 10 Jun 2009 Posts: 102
|
Posted: Tue Sep 01, 2009 10:20 am Post subject: |
|
|
Finally realized the solution a couple of days ago. (All though it looks like someone has solved the problem since the last time I checked the post.) Instead of using spaces to divide the individual fields and quotes to encapsulate fields with spaces, use a non-printing ascii character to separate fields such as the Unit Separator.
| Code: | Variable := "she" . chr(31) . "sells" . chr(31) . "sea" . chr(31) . "shells" . chr(31) . "by the sea shore"
msgbox %Variable%
A_UnitSeparator := chr(31)
msgbox %A_UnitSeparator%
StringSplit, OutputArray, Variable, %A_UnitSeparator%,
msgbox %OutputArray0%
Loop, %OutputArray0%
{
msgbox % OutputArray%A_Index%
} |
I don't discount the other solution just yet though. All though this method allows for the simple serialization and deserialization of strings within a program, it would be entirely inefficient or impossible to force users to input data this way. The other solution allows for the processing of regular user input. |
|
| Back to top |
|
 |
Kar.ma
Joined: 19 Jan 2011 Posts: 1
|
Posted: Wed Jan 19, 2011 5:21 pm Post subject: |
|
|
Thanks lrh9, I registered to this forum to thank you.
Your last solution is what I needed.
Let me point out that you don't need to use a strange character like the chr(31) (passed with a variable), and that this one works too:
| Code: | Variable := "she|sells|sea|shells|by the sea shore"
msgbox %Variable%
A_UnitSeparator := "|"
msgbox %A_UnitSeparator%
StringSplit, OutputArray, Variable, %A_UnitSeparator%,
msgbox %OutputArray0%
Loop, %OutputArray0%
{
msgbox % OutputArray%A_Index%
} |
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|