[REGEX] How to capture any color text value on the fly ? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

[REGEX] How to capture any color text value on the fly ?

02 Sep 2019, 15:33

Hello,
In this example RGB value " 777,0,0 " witch is not a valid RGB value is also captured. How to avoid this? :think:
If i remove the first 3 letters from the variable, value " 800000 " is not captured why ?

Code: Select all

var=
(
try
800000	777,0,0 kldjfdoifj 12,12,3 dfjiosjf jksdi
8000AA	128,0,0 125,125,125|255,254,253 0xffaabb
FF0000	256,0,0
FFA500	257,165,0
FFFF00	550,255,0
808000	128,128,0
008000	0,128,0
Color Name	Hex Code
RGB	Decimal Code
RGB
800080	128,0,128
FF00FF	255,0,255
00FF00	0,255,0
008080	0,128,128
00FFFF	0,255,255
0000FF	0,0,255
 Name	Hex Code
RGB	Decimal Code
RGB
000080	0,0,128
000000	0,0,0
808080	128,128,128
C0C0C0	192,192,192
FFFFFF	255,255,255
)

colors:=[]
p:=0

while p:=RegExMatch(var, "[0-9a-fA-F]{6}|(\d{1,3}) ?, ?(\d{1,3}) ?, ?(\d{1,3})", color%a_index%,  p+strlen("color" %a_index%)) 
{
colors.push(color%a_index%)
}

msgbox, % st_printarr(colors)


; (by tidbit)
st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}
Thanks
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: [REGEX] How to capture any color text value on the fly ?

02 Sep 2019, 16:23

Code: Select all

var=
(
try
800000	777,0,0 kldjfdoifj 12,12,3 dfjiosjf jksdi
8000AA	128,0,0 125,125,125|255,254,253 0xffaabb
FF0000	256,0,0
FFA500	257,165,0
FFFF00	550,255,0
808000	128,128,0
008000	0,128,0
Color Name	Hex Code
RGB	Decimal Code
RGB
800080	128,0,128
FF00FF	255,0,255
00FF00	0,255,0
008080	0,128,128
00FFFF	0,255,255
0000FF	0,0,255
 Name	Hex Code
RGB	Decimal Code
RGB
000080	0,0,128
000000	0,0,0
808080	128,128,128
C0C0C0	192,192,192
FFFFFF	255,255,255
)

colors:=[]
pos := 1

while (pos := RegExMatch(var, "[[:xdigit:]]{6}|(\d{1,3}) ?, ?(\d{1,3}) ?, ?(\d{1,3})", m, pos + StrLen(m)))
{
	if (StrLen(m) = 6 || inclusiveAllBetween(0, 255, m1, m2, m3))
		colors.push(m)
}

msgbox, % st_printarr(colors)

inclusiveAllBetween(min, max, Vars*) {
	if !Vars.Count()
		return false

	for each, var in Vars
		if (var < min || var > max)
			return false
	
	return true
}

; (by tidbit)
st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: [REGEX] How to capture any color text value on the fly ?

02 Sep 2019, 16:49

Code: Select all

var=
(
try
800000	777,0,0 kldjfdoifj 12,12,3 dfjiosjf jksdi
8000AA	128,0,0 125,125,125|255,254,253 0xffaabb
FF0000	256,0,0
FFA500	257,165,0
FFFF00	550,255,0
808000	128,128,0
008000	0,128,0
Color Name	Hex Code
RGB	Decimal Code
RGB
800080	128,0,128
FF00FF	255,0,255
00FF00	0,255,0
008080	0,128,128
00FFFF	0,255,255
0000FF	0,0,255
 Name	Hex Code
RGB	Decimal Code
RGB
000080	0,0,128
000000	0,0,0
808080	128,128,128
C0C0C0	192,192,192
FFFFFF	255,255,255
)

p := "(1|(2))? (?(-1)((5)|[0-4])|\d)? (?(-1)[0-5]|\d)"
while RegExMatch(var, "im`axO)^[\da-f]{6} | \D\K" . p . "," . p . "," . p . "(?=\D|$)", m, m ? m.Pos + m.Len : 1)
   str .= "[" . A_Index . "] =>> " . m[0] . "`n"

MsgBox, % str
I'm not sure if 0xffaabb should be captured.
User avatar
boiler
Posts: 16771
Joined: 21 Dec 2014, 02:44

Re: [REGEX] How to capture any color text value on the fly ?

02 Sep 2019, 20:02

swagfag wrote:
02 Sep 2019, 16:23

Code: Select all

var=
(
try
800000	777,0,0 kldjfdoifj 12,12,3 dfjiosjf jksdi
8000AA	128,0,0 125,125,125|255,254,253 0xffaabb
FF0000	256,0,0
FFA500	257,165,0
FFFF00	550,255,0
808000	128,128,0
008000	0,128,0
Color Name	Hex Code
RGB	Decimal Code
RGB
800080	128,0,128
FF00FF	255,0,255
00FF00	0,255,0
008080	0,128,128
00FFFF	0,255,255
0000FF	0,0,255
 Name	Hex Code
RGB	Decimal Code
RGB
000080	0,0,128
000000	0,0,0
808080	128,128,128
C0C0C0	192,192,192
FFFFFF	255,255,255
)

colors:=[]
pos := 1

while (pos := RegExMatch(var, "[[:xdigit:]]{6}|(\d{1,3}) ?, ?(\d{1,3}) ?, ?(\d{1,3})", m, pos + StrLen(m)))
{
	if (StrLen(m) = 6 || inclusiveAllBetween(0, 255, m1, m2, m3))
		colors.push(m)
}

msgbox, % st_printarr(colors)

inclusiveAllBetween(min, max, Vars*) {
	if !Vars.Count()
		return false

	for each, var in Vars
		if (var < min || var > max)
			return false
	
	return true
}

; (by tidbit)
st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}
This is not capturing any of the valid RGB trio of values like 257,165,0. He's not looking to capture only the hex values, he also wants the trios of decimal values but only if they're valid (0-255) which 777,0,0 isn't.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 01:09

it matches any 6 hexchars in a row and any comma separated triplets, then stores only the hexchars and valid triplets. 257 and 777 arent stored
User avatar
hoppfrosch
Posts: 443
Joined: 07 Oct 2013, 04:05
Location: Rhine-Maine-Area, Hesse, Germany
Contact:

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 03:42

A pure regex-solution to match your 0...255 triples - it uses a more specialized regex than your simple \d{1-3}

(https://regex101.com/r/5hwzOS/1)

Code: Select all

var=
(
try
800000	777,0,0 kldjfdoifj 12,12,3 dfjiosjf jksdi
8000AA	128,0,0 125,125,125|255,254,253 0xffaabb
FF0000	256,0,0
FFA500	257,165,0
FFFF00	550,255,0
808000	128,128,0
008000	0,128,0
Color Name	Hex Code
RGB	Decimal Code
RGB
800080	128,0,128
FF00FF	255,0,255
00FF00	0,255,0
008080	0,128,128
00FFFF	0,255,255
0000FF	0,0,255
 Name	Hex Code
RGB	Decimal Code
RGB
000080	0,0,128
000000	0,0,0
808080	128,128,128
C0C0C0	192,192,192
FFFFFF	255,255,255
)

colors:=[]
p:=0

re_255 := "\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b"
while p:=RegExMatch(var, "[0-9a-fA-F]{6}|(" re_255 ") ?, ?(" re_255 ") ?, ?(" re_255 ")", color%a_index%,  p+strlen("color" %a_index%)) 
{
colors.push(color%a_index%)
}

msgbox, % st_printarr(colors)


; (by tidbit)
st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 04:33

Because of this post by @malcev:

Code: Select all

#NoEnv
var=
(
800000	777,0,0 kldjfdoifj 12,12,3 dfjiosjf jksdi
8000AA	128,0,0 125,125,125|255,254,253 0xffaabb
FF0000	256,0,0
FFA500	257,165,0
FFFF00	550,255,0
808000	128,128,0
008000	0,128,0
Color Name	Hex Code
RGB	Decimal Code
RGB
800080	128,0,128
FF00FF	255,0,255
00FF00	0,255,0
008080	0,128,128
00FFFF	0,255,255
0000FF	0,0,255
 Name	Hex Code
RGB	Decimal Code
RGB
000080	0,0,128
000000	0,0,0
808080	128,128,128
C0C0C0	192,192,192
FFFFFF	255,255,255
)

colors:=[]
p := 1
m := ""
while (p := RegExMatch(var, "[[:xdigit:]]{6}|\b\d{1,3}\s?,\s?\d{1,3}\s?,\s?\d{1,3}\b(?CCheckRGB)", m, p + strlen(m)))
{
   color%a_index% := m ; why do you need the pseudo-array?
   colors.push(color%a_index%)
}


msgbox, % st_printarr(colors)
ExitApp

CheckRGB(Match) {
   Loop, Parse, Match, `,, %A_Space%
      If (A_LoopField > 255) {
         MsgBox, 16, %A_ThisFunc%, Invalid RGB value %Match%! ; for testing
         Return 1
      }
}


; (by tidbit)
st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 04:58

teadrinker wrote:
02 Sep 2019, 16:49
I'm not sure if 0xffaabb should be captured.
Yes, it should but without the "0x" prefix
hoppfrosch wrote:
03 Sep 2019, 03:42
boiler wrote:
02 Sep 2019, 20:02
This is not capturing any of the valid RGB trio of values like 257,165,0.
Yes, the script does that. :!: Like me, you are probably using an older version of AHK. Replace !Vars.Count() by !Vars.maxindex() to fix the problem.
hoppfrosch wrote:
03 Sep 2019, 03:42
A pure regex-solution to match your 0...255 triples - it uses a more specialized regex than your simple \d{1-3}
Thanks, could you make it so it also match 255,0,000 or 12,00,07 format ?

swagfag code is the closest to what I'm looking for. I forgot to mention it, the StrLen() jumping feature should only applies to R,G,B format and not to hex #RGB format. I modified swagfag code to make it more tolerant regarding hex RGB value so that for a string like "backgroundFFAAFF" , "dFFAAF" and "FFAAFF" values will be both captured.

I still have a major problem. :(
Why is the first value " 80FF80 " not captured in this new example ? :think:

Code: Select all

var=
(
80FF80
backgroundFFAAFF
8000AA	128,000,0
800000	777,0,0 kldjfdoifj 12,12,3 dfjiosjf jksdi
8000AA	128,0,0 
125,000,00|
(255,254,253) 0xffaabb
FF0000	256,0,0
FFA500	257,165,0
RGB	Decimal Code
RGB
000080	0,0,128
000000	0,0,0
808080	128,128,128
C0C0C0	192,192,192
FFFFFF	255,255,255
)


clipboard:=var

colors:=[]
pos := 1

while (pos := RegExMatch(clipboard, "[[:xdigit:]]{6}|(\d{1,3}) ?, ?(\d{1,3}) ?, ?(\d{1,3})", m, (instr(m,",")) ? pos + StrLen(m) : pos+1))
{

	if (StrLen(m) = 6 || inclusiveAllBetween(0, 255, m1, m2, m3))
		colors.push(m)
}

msgbox, % st_printarr(colors)

inclusiveAllBetween(min, max, Vars*) {
	if !Vars.maxindex()
		return false

	for each, var in Vars
		if (var < min || var > max)
			return false
	
	return true
}

; (by tidbit)
st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}

Tanks for your help :think:
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 05:14

... so that for a string like "backgroundFFAAFF" , "dFFAAF" and "FFAAFF" values will be both captured.
Would you please explain the reason?
What should be captured for a string like 0123456789ABCDEF?
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 05:30

just me wrote:
03 Sep 2019, 05:14
Would you please explain the reason?
It's for upgrading my color viewer tool. https://www.autohotkey.com/boards/viewtopic.php?f=6&t=67586 8-)
just me wrote:
03 Sep 2019, 05:14
What should be captured for a string like 0123456789ABCDEF?
All possible combinations should be captured : 012345, 123456, 234567, 345678, 456789, 56789A, 6789AB, 789ABC, 89ABCD, 9ABCDE, ABCDEF, reading form left to right.
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 05:48

I think that neither backgroundFFAAFF nor any of the substrings of 0123456789ABCDEF is actually a RGB color value, so it makes no sense for me. But

Code: Select all

pos := 0 ; changed from 1
m := ""
while (pos := RegExMatch(clipboard, "[[:xdigit:]]{6}|(\d{1,3}) ?, ?(\d{1,3}) ?, ?(\d{1,3})", m, (instr(m,",")) ? pos + StrLen(m) : pos+1))
{
should do what you want (the first match will be searched at position 1, not 2).
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 06:13

hoppfrosch wrote: A pure regex-solution to match your 0...255 triples
It could be shortened:

Code: Select all

re_255 := "\b(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\b"
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 07:12

just me wrote:
03 Sep 2019, 05:48
I think that neither backgroundFFAAFF nor any of the substrings of 0123456789ABCDEF is actually a RGB color value, so it makes no sense for me.
The tool I created will display any selected value. Suppose you want to know what "456789" looks like in string "0123456789ABCDEF" is it red, blue or green? I'm a lazy person and instead of selecting the exact value with a mouse drag I'll just double click to select the entire word press a keyboard shortcut and immediately see that the value 456789 is blue. That's why the script must be very permissive. (Same for "backgroundFFAAFF") ;)
just me wrote:
03 Sep 2019, 05:48
this should do what you want (the first match will be searched at position 1, not 2)
why I hadn't thought of that. :facepalm: Your script works now perfectly. :thumbup: Thank you very much for your help. :clap:
User avatar
boiler
Posts: 16771
Joined: 21 Dec 2014, 02:44

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 07:57

SpeedMaster wrote:
03 Sep 2019, 04:58
Like me, you are probably using an older version of AHK.
Ah, yes. Thanks.
User avatar
hoppfrosch
Posts: 443
Joined: 07 Oct 2013, 04:05
Location: Rhine-Maine-Area, Hesse, Germany
Contact:

Re: [REGEX] How to capture any color text value on the fly ?

03 Sep 2019, 23:19

SpeedMaster wrote:
03 Sep 2019, 04:58
hoppfrosch wrote:
03 Sep 2019, 03:42
A pure regex-solution to match your 0...255 triples - it uses a more specialized regex than your simple \d{1-3}
Thanks, could you make it so it also match 255,0,000 or 12,00,07 format ?
For sure ... https://regex101.com/r/iJ3fUc/1:

The regex has to be:

Code: Select all

re_255  := "\b([0-1]{0,1}[0-9]{0,1}[0-9]|2[0-4][0-9]|25[0-5])\b"
As teadrinker mentioned, this expression could be shortened by replacing [0-9] with \d ....

Code: Select all

re_255  := "\b([0-1]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\b"
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: [REGEX] How to capture any color text value on the fly ?  Topic is solved

04 Sep 2019, 16:42

hoppfrosch wrote:
03 Sep 2019, 23:19
For sure ...
Thanks, I will keep that in my my personal Regex Black Book. ;)

I'm still wondering why I have to add 4 letters to the variable var to capture the first value (var:="abcd" . var).
Even if I have set the position p to zero (p:=0)
:think:

Code: Select all

#SingleInstance force
var=
(
BBDDBC	777,0,0 kldjfdoifj 128,02,3 dfjiosjf jksdi
7000AA	128,0,0 125,125, 125|255,254,253 0xffaabb
FF0000	256,0,0
FFA500	257, 165, 0
FFFF00	550,255,0
808000	128, 128,0
008000	0,128,0
Color Name	Hex Code
RGB	Decimal Code
RGB
800080	128,0,128
FF00FF	255,000,255
00FF00	0000000,100,0
008080	0,128,128
00FFFF	0,255,255
0000FF	0,0,255
 Name	Hex Code
RGB	Decimal Code
RGB
000080	0,0,128
000000	1,0, 000
808080	rgb(123,123,123)
C0C0C0	192,192,192
FFFFFF	255,255,255
)


colors:=[]
p:=0

re_255 := "\b([0-1]{0,1}[0-9]{0,1}[0-9]|2[0-4][0-9]|25[0-5])\b"
while p:=RegExMatch(var, "[0-9a-fA-F]{6}|(" re_255 ")\s?,\s?(" re_255 ")\s?,\s?(" re_255 ")", m, (m || m=0) ? p+strlen(m) : 1)
{
colors.push(m)
}

msgbox, % st_printarr(colors)


; (by tidbit)
st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}
User avatar
lmstearn
Posts: 688
Joined: 11 Aug 2016, 02:32
Contact:

Re: [REGEX] How to capture any color text value on the fly ?

18 Mar 2021, 23:07

Came across this while searching for a general validation for hex RGB.
As an alternative to

Code: Select all

RegExMatch(var, "[0-9a-fA-F]{6}")
Why not bounce it against GetNearestColor?

Code: Select all

; Want WM_CTLCOLORSTATIC or similar
myHDC := DllCall("user32\GetDC", "Ptr", myHWnd, "Ptr")
CLR_INVALID := 16777215 ; 0xFFFFFFFF
	nearestcolour := DllCall("Gdi32.dll\GetNearestColor", "Ptr", myHDC, "UInt", someHexColour)
	if (nearestcolour == CLR_INVALID)
	msgbox Cannot retrieve nearest colour!
DllCall("ReleaseDC", "UPtr", myHWnd, "UPtr", myHDC)
The tradeoff from the performance hit over the regex is the possibility of a nearest colour. :)
Edit: Oops, that is for the System Palette only. So not much use. :(
:arrow: itros "ylbbub eht tuO kaerB" a ni kcuts m'I pleH

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: tiska and 114 guests