Page 1 of 2

String Manipulation between ^ and /

Posted: 10 May 2024, 17:45
by trevzilla
If I have a string that looks similar to this:

%B1111222233334444^LastName/FirstName

How could I select JUST the LastName and store that to a variable? I feel like I need to "find" the ^ and the / characters and select everything in-between those.

Any ideas?

Re: String Manipulation between ^ and /

Posted: 10 May 2024, 18:32
by sofista
One way is to use a Regular Expression, as follows:

Code: Select all

str := " %B1111222233334444^LastName/FirstName"
RegExMatch(str, ".*\^\K(.+)/", &m)
MsgBox(m[1])

Re: String Manipulation between ^ and /

Posted: 10 May 2024, 20:52
by boiler
Another way:

Code: Select all

str := '%B1111222233334444^LastName/FirstName'
MsgBox LName := Strsplit(StrSplit(str,'^')[2],'/')[1]

Re: String Manipulation between ^ and /

Posted: 10 May 2024, 21:08
by flyingDman
or:

Code: Select all

str := '%B1111222233334444^LastName/FirstName'
MsgBox LName := StrSplit(str,['^','/'])[2]

Re: String Manipulation between ^ and /

Posted: 10 May 2024, 21:31
by trevzilla
Amazing! Thank you all! I'll try these out soon.

Re: String Manipulation between ^ and /

Posted: 11 May 2024, 12:48
by andymbody
one more... in case you want to build on this to separate the different parts of the string, and refer to them by name

Code: Select all

str := ' %B1111222233334444^LastName/FirstName something else'
RegExMatch(str, '\^(?<lName>[^/]+)/(?<fName>(?i)[a-z]+)', &m)
MsgBox("first: " m.fName " last: " m.lName)

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 02:04
by xMaxrayx
if you want learn regex which is used a lot with other programming languages for text you can use regex101.

https://regex101.com
https://regexlearn.com

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 11:53
by trevzilla
I have used RegEx a bit with Bulk Rename Utility. I definitely see the power in it, I'm just not very good with it yet. As soon as these solutions were posted, it was an "ah ha! Of course the answer is RegEx!" moment.

With that said I put into place the solution by flyingDman - only because it made the most sense to me. I'm sure the other solutions would work as well, so thank you for those.

My next RegEx question is this. My string also has a big long section in that "something else" part which includes an = sign. I need to get the first two digits after the equal into one variable, and the next two digits into another variable.
The string looks similar to this:
blahblahblah=YYMMblahblahblah
Can you help me use RegEx to put the YY into a "year" variable and the MM into a "month" variable?

Thank you so much!
(I'll keep looking into it myself...but I bet you all could help in about 30 seconds, where it'll take me about 3 hours to figure it out. :D )

edit: Seems like I should use a "look behind" similar to this:
(?<==)\d\d

But my syntax is wrong, and I don't know how to fix it. How do I do a look behind when the character I'm looking behind IS an equal sign?

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 12:36
by flyingDman

Code: Select all

str := "blahblahblah=YYMMblahblahblah"
msgbox year := substr(str,instr(str,"=")+1,2)
msgbox month := substr(str,instr(str,"=")+3,2)

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 12:47
by trevzilla
That did the trick! Thank you flyingDman! I was definitely going down the wrong path.

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 13:57
by sofista
trevzilla, just to answer your RegEx question:

Code: Select all

str := "blahblahblah=YYMMblahblahblah"
RegExMatch(str, "=(?<year>(..))(?<month>(..))", &m)
MsgBox(m.year "`n" m.month)

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 14:44
by teadrinker
@sofista
You have extra parentheses: RegExMatch(str, "=(?<year>..)(?<month>..)", &m)

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 15:05
by sofista
teadrinker wrote:
13 May 2024, 14:44
@sofista
You have extra parentheses: RegExMatch(str, "=(?<year>..)(?<month>..)", &m)
Good catch :thumbup:

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 15:32
by trevzilla
I hope it's OK that I keep this thread alive for my next question. I feel like my script is SOO close. I thought I had it, but as I opened it up to a few testers, this string popped up:

RandomDigits^Lname/Fname(sometimes spaces here, sometimes not)^RandomDigits

I thought there would always be a space after Fname, so to get the Fname variable, my code uses the strsplit solution looking for the / and the first space...but now I have to find the characters between the / and the first space OR another ^.

My current RegEx looks like this:
FName := StrSplit(str,['/',' '])[2]

How do I modify that to look for the 2nd caret in the string OR a space? (Or it could always just look for the second caret, and delete any preceding spaces before the caret if they exist)

Again, I really appreciate the help. My colleague was over the moon when I showed her the "Alpha" product, and this script is going to save us SOO much time!

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 16:40
by flyingDman
I don' t understand. This still works as expected:
str := '8181818^Lname/Fname ^1818181'
MsgBox LName := StrSplit(str,['^','/'])[2]

Is that not the intended result?

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 16:58
by trevzilla
I'm sorry I wasn't clear. Yes, your solution works perfectly to get Lname into a variable. However my follow-up question is regarding Fname.

I was trying to apply your solution to get Fname as well. But sometimes there is a space behind Fname, and sometimes there is a ^ behind it.

For example, my RegEx should match JUST Fname in all the following strings:
  • 54545454^Lname/Fname ^5646416516511
  • 54545454^Lname/Fname^5646416516511
  • 54545454^Lname/Fname M.I. ^5646416516511

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 17:24
by Seven0528

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force

needle := "\^(?P<Lname>\w+)/(?P<Fname>\w+)"
haystacks := ["54545454^Lname/Fname ^5646416516511"
    ,"54545454^Lname/Fname^5646416516511"
    ,"54545454^Lname/Fname M.I. ^5646416516511"]
for haystack in haystacks    {
    if (regExMatch(haystack, needle, &m))
        msgBox(m.Lname ", " m.Fname)
}
 @trevzilla
This is similar to @andymbody's code.
My code has better readability, while andymbody's code is more efficient.
There isn't a significant difference, though.
https://www.autohotkey.com/docs/v2/lib/RegExMatch.htm#Remarks wrote:A subpattern may be given a name such as the word Year in the pattern (?P<Year>\d{4}).
https://www.pcre.org/original/doc/html/pcrepattern.html wrote:In PCRE, a subpattern can be named in one of three ways: (?<name>...) or (?'name'...) as in Perl, or (?P<name>...) as in Python.

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 17:53
by trevzilla
Ah, I understand now. I was pretty lost reading andymbody's code above, but funny...it was exactly what I needed. Thank you for pointing that out to me, and feel like I understand how it's working now.

From what I can tell, my script is fully working! Couldn't have done it without you all!

Re: String Manipulation between ^ and /

Posted: 13 May 2024, 18:30
by flyingDman
Be careful with compounded first names. What if you have a first name like Billy Jean or T.J. or Daisy-Mae. Are you sure you want to have those names as Billy or T or Daisy?

Re: String Manipulation between ^ and /

Posted: 14 May 2024, 06:43
by andymbody
flyingDman wrote:
13 May 2024, 18:30
Be careful with compounded first names. What if you have a first name like Billy Jean or T.J. or Daisy-Mae. Are you sure you want to have those names as Billy or T or Daisy?
Good point... and yours does a good job of supporting these cases. Your solutions are always interesting.

In case the regex is desirable, this tweak should provide support as well.

Code: Select all

#Requires AutoHotkey v2+
#SingleInstance Force

str :=
(
"54545454^Zeta-Jones/Catherine^564641651651
54545454^Jones/James Earl ^5646416516511
54545454^Fox/Michael J. ^5646416516511
54545454^Watt/J.J.^5646416516511
54545454^Adams/T^5646416516511
54545454^O'Connell/Billie Eilish Pirate Baird ^5646416516511
54545454^Duke/Daisy-Mae^5646416516511"
)
; multi-line not needed here but might be in your case
; also the trailing \h*\^ is not needed, but is there in case you wish to extend the needle
; did not use \w because this would match numbers, which may cause issues in some cases
; added support for hyphens, apostrophe and chained names
; this does not require any space trims of fName, but you can shorten the needle if you want to trim instead
; can also support fName/lName - just swap the variable names
needle	:= "im)\^(?<lName>[a-z.'-]+)/(?<fName>(?1)( (?1))*)\h*\^"
;needle	:= "im)\^(?<lName>[a-z .'-]+)/(?<fName>(?1))"	; requires trim of fName

newStr := ''
Loop parse, str, '`n', '`r'
{
	if (RegExMatch(A_LoopField, needle, &m))
		newStr .= m.fName "," m.lName "`n"	; comma included to show that trailing space was not captured
}
MsgBox newStr
results
Catherine,Zeta-Jones
James Earl,Jones
Michael J.,Fox
J.J.,Watt
T,Adams
Billie Eilish Pirate Baird,O'Connell
Daisy-Mae,Duke