feat: string parsers developed for all formats with strict regex

NOTE: this will be diluted down in order to admit any type of weird
string
This commit is contained in:
2025-08-15 17:44:36 +02:00
parent 5ffeee7851
commit 2fc069ca8e
8 changed files with 266 additions and 1 deletions

View File

@@ -1,4 +1,5 @@
use crate::color::{ColorHue, HSL, Percentage, RGB};
use regex::Regex;
impl HSL {
pub fn new(h: u16, s: u8, l: u8) -> Self {
@@ -20,6 +21,28 @@ impl PartialEq for HSL {
}
}
// TODO: manage error
impl From<String> for HSL {
fn from(value: String) -> Self {
let regex = Regex::new(r"hsl\(([0-9]+),([0-9]+),([0-9 ]+)\)").unwrap();
let numbers = value.replace(" ", "").replace("%", "");
let result = regex.captures(&numbers);
match result {
Some(value_list) => {
// Numeric
let h: u16 = value_list[1].parse::<u16>().unwrap();
let s: u8 = value_list[2].parse::<u8>().unwrap();
let l: u8 = value_list[3].parse::<u8>().unwrap();
return Self::new(h, s, l);
}
None => (),
}
Self::new(0, 0, 0)
}
}
impl From<RGB> for HSL {
fn from(value: RGB) -> Self {
let r = value.0.to_f32() / 255.0;

View File

@@ -1,3 +1,4 @@
use regex::Regex;
use std::fmt::Display;
use crate::color::{ColorHue, HSV, Percentage, RGB};
@@ -28,6 +29,28 @@ impl PartialEq for HSV {
}
}
// TODO: manage error
impl From<String> for HSV {
fn from(value: String) -> Self {
let regex = Regex::new(r"hsv\(([0-9]+),([0-9]+),([0-9 ]+)\)").unwrap();
let numbers = value.replace(" ", "").replace("%", "");
let result = regex.captures(&numbers);
match result {
Some(value_list) => {
// Numeric
let h: u16 = value_list[1].parse::<u16>().unwrap();
let s: u8 = value_list[2].parse::<u8>().unwrap();
let v: u8 = value_list[3].parse::<u8>().unwrap();
return Self::new(h, s, v);
}
None => (),
}
Self::new(0, 0, 0)
}
}
impl From<RGB> for HSV {
fn from(color: RGB) -> Self {
let r = color.0.to_f32() / 255.0;

View File

@@ -8,6 +8,8 @@ pub mod rgb;
use std::fmt::UpperHex;
use regex::Regex;
use crate::core::ranged::RangedInt;
pub type ColorIntensity = RangedInt<0, 255>;
@@ -22,7 +24,47 @@ pub struct HSV(ColorHue, Percentage, Percentage);
#[derive(Debug)]
pub struct Color(RGB);
impl Color {}
impl Color {
pub fn try_parse(input: String) -> Result<Color, ()> {
let input = input.replace(" ", "").to_uppercase();
let hex_regex = Regex::new(r".*(#[a-fA-F0-9]{3,6}).*").unwrap();
let rgb_regex =
Regex::new(r"(rgb\([ ]*[0-9]+[ ]*,[ ]*[0-9]+[ ]*,[ ]*[0-9 ]+[ ]*\)).*").unwrap();
let hsl_regex =
Regex::new(r"(hsl\([ ]*[0-9]+[ ]*,[0-9]+[ ]*[%]*[ ]*,[0-9 ]+[ ]*[%]*[ ]*\)).*")
.unwrap();
let hsv_regex =
Regex::new(r"(hsv\([ ]*[0-9]+[ ]*,[0-9]+[ ]*[%]*[ ]*,[0-9 ]+[ ]*[%]*[ ]*\)).*")
.unwrap();
let hex_result = hex_regex.captures(&input);
match hex_result {
Some(color) => return Ok(Color::from(RGB::from(color[1].to_string()))),
None => (),
}
let rgb_result = rgb_regex.captures(&input);
match rgb_result {
Some(color) => return Ok(Color::from(RGB::from(color[1].to_string()))),
None => (),
}
let hsl_result = hsl_regex.captures(&input);
match hsl_result {
Some(color) => return Ok(Color::from(HSL::from(color[1].to_string()))),
None => (),
}
let hsv_result = hsv_regex.captures(&input);
match hsv_result {
Some(color) => return Ok(Color::from(HSV::from(color[1].to_string()))),
None => (),
}
Err(())
}
}
impl UpperHex for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@@ -1,3 +1,4 @@
use regex::Regex;
use std::fmt::{Display, UpperHex};
use crate::{
@@ -15,6 +16,39 @@ impl RGB {
}
}
// TODO: manage error
impl From<String> for RGB {
fn from(value: String) -> Self {
let regex = Regex::new(r"rgb\(([0-9]+),([0-9]+),([0-9 ]+)\)").unwrap();
let mut numbers = value.replace(" ", "");
let result = regex.captures(&numbers);
match result {
Some(value_list) => {
// Numeric
let r: u8 = value_list[1].parse::<u8>().unwrap();
let g: u8 = value_list[2].parse::<u8>().unwrap();
let b: u8 = value_list[3].parse::<u8>().unwrap();
return Self::new(r, g, b);
}
None => {
// Hex
if numbers.len() == 7 {
numbers.remove(0);
let hex = numbers.split_at(2);
let r = u8::from_str_radix(hex.0, 16).unwrap();
let hex = hex.1.split_at(2);
let g = u8::from_str_radix(hex.0, 16).unwrap();
let b = u8::from_str_radix(hex.1, 16).unwrap();
return Self::new(r, g, b);
}
}
}
Self::new(0, 0, 0)
}
}
impl PartialEq for RGB {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0 && self.1 == other.1 && self.2 == other.2

View File

@@ -162,4 +162,93 @@ pub mod tests {
let color = HSV::new(142, 92, 94);
assert_eq!(RGB::from(color), RGB::new(19, 240, 100));
}
#[test]
fn test_rgb_string_parse() {
// Base colors
// HEX
let color = "#FF0000";
assert_eq!(RGB::from(color.to_string()), RGB::new(255, 0, 0));
let color = "#00FF00";
assert_eq!(RGB::from(color.to_string()), RGB::new(0, 255, 0));
let color = "#0000FF";
assert_eq!(RGB::from(color.to_string()), RGB::new(0, 0, 255));
// RGB
let color = "rgb(255 ,0,0)";
assert_eq!(RGB::from(color.to_string()), RGB::new(255, 0, 0));
let color = "rgb(0,255, 0)";
assert_eq!(RGB::from(color.to_string()), RGB::new(0, 255, 0));
let color = "rgb(0 , 0, 255)";
assert_eq!(RGB::from(color.to_string()), RGB::new(0, 0, 255));
// Complex colors
// HEX
let color = "#Ffb703";
assert_eq!(RGB::from(color.to_string()), RGB::new(255, 183, 3));
let color = "#588157";
assert_eq!(RGB::from(color.to_string()), RGB::new(88, 129, 87));
let color = "#fB8500";
assert_eq!(RGB::from(color.to_string()), RGB::new(251, 133, 0));
let color = "#8338eC";
assert_eq!(RGB::from(color.to_string()), RGB::new(131, 56, 236));
let color = "#9D8189";
assert_eq!(RGB::from(color.to_string()), RGB::new(157, 129, 137));
// RGB
let color = "rgb(255, 183, 3)";
assert_eq!(RGB::from(color.to_string()), RGB::new(255, 183, 3));
let color = "rgb(88, 129, 87)";
assert_eq!(RGB::from(color.to_string()), RGB::new(88, 129, 87));
let color = "rgb(251, 133, 0)";
assert_eq!(RGB::from(color.to_string()), RGB::new(251, 133, 0));
let color = "rgb(131, 56, 236)";
assert_eq!(RGB::from(color.to_string()), RGB::new(131, 56, 236));
let color = "rgb(157, 129, 137)";
assert_eq!(RGB::from(color.to_string()), RGB::new(157, 129, 137));
}
#[test]
fn test_hsl_string_parse() {
// Base colors
let color = "hsl(0, 100, 50)";
assert_eq!(HSL::from(color.to_string()), HSL::new(0, 100, 50));
let color = "hsl(120, 100, 50)";
assert_eq!(HSL::from(color.to_string()), HSL::new(120, 100, 50));
let color = "hsl(240, 100, 50)";
assert_eq!(HSL::from(color.to_string()), HSL::new(240, 100, 50));
// Complex colors
let color = "hsl(255 , 83, 3)";
assert_eq!(HSL::from(color.to_string()), HSL::new(255, 83, 3));
let color = "hsl(88 , 29,87)";
assert_eq!(HSL::from(color.to_string()), HSL::new(88, 29, 87));
let color = "hsl(251,33,0)";
assert_eq!(HSL::from(color.to_string()), HSL::new(251, 33, 0));
let color = "hsl(131,56,36)";
assert_eq!(HSL::from(color.to_string()), HSL::new(131, 56, 36));
let color = "hsl(157,29, 37 )";
assert_eq!(HSL::from(color.to_string()), HSL::new(157, 29, 37));
}
#[test]
fn test_hsv_string_parse() {
// Base colors
let color = "hsv(0, 100, 50)";
assert_eq!(HSV::from(color.to_string()), HSV::new(0, 100, 50));
let color = "hsv(120, 100, 50)";
assert_eq!(HSV::from(color.to_string()), HSV::new(120, 100, 50));
let color = "hsv(240, 100, 50)";
assert_eq!(HSV::from(color.to_string()), HSV::new(240, 100, 50));
// Complex colors
let color = "hsv(255 , 83, 3)";
assert_eq!(HSV::from(color.to_string()), HSV::new(255, 83, 3));
let color = "hsv(88 , 29,87)";
assert_eq!(HSV::from(color.to_string()), HSV::new(88, 29, 87));
let color = "hsv(251,33,0)";
assert_eq!(HSV::from(color.to_string()), HSV::new(251, 33, 0));
let color = "hsv(131,56,36)";
assert_eq!(HSV::from(color.to_string()), HSV::new(131, 56, 36));
let color = "hsv(157,29, 37 )";
assert_eq!(HSV::from(color.to_string()), HSV::new(157, 29, 37));
}
}

View File

@@ -1,6 +1,7 @@
use clipboard::ClipboardContext;
use clipboard::ClipboardProvider;
use crate::color::Color;
use crate::color::HSV;
use crate::color::RGB;
@@ -20,4 +21,11 @@ fn main() {
let color = RGB::new(220, 10, 50);
let hsv_color = HSV::from(RGB::new(220, 10, 50));
println!("RGB color: {}, HSV Color: {}", color, hsv_color);
Color::try_parse("#F2FA01".to_string());
Color::try_parse("rgb(1, 3,4)".to_string());
Color::try_parse("rgb(1,3 ,4)".to_string());
Color::try_parse("rgb(1,F,4)".to_string());
Color::try_parse("hsl(100,100%,40%)".to_string());
Color::try_parse("hsl(100,100%,40)".to_string());
}