From 3029bf661aa8a533957ac212b6746e1db19beec4 Mon Sep 17 00:00:00 2001 From: despiegk Date: Thu, 21 Aug 2025 11:37:17 +0200 Subject: [PATCH] ... --- examples/data/countries.vsh | 10 +++- lib/data/countries/README.md | 77 ++++++++++++++++++++++++++ lib/data/countries/factory.v | 101 +++++++++++++++++++++++------------ lib/data/countries/model.v | 1 + 4 files changed, 152 insertions(+), 37 deletions(-) create mode 100644 lib/data/countries/README.md diff --git a/examples/data/countries.vsh b/examples/data/countries.vsh index 7fda2020..4566462c 100755 --- a/examples/data/countries.vsh +++ b/examples/data/countries.vsh @@ -18,7 +18,7 @@ for i, country in all_countries { // --- Example: Find a specific country (e.g., Belgium) --- println('\n--- Searching for Belgium ---') -found := false +mut found := false for country in all_countries { if country.iso == 'BE' { println('Found Belgium: ${country.str()}') @@ -41,4 +41,10 @@ for country in all_countries { println('Found ${eu_countries.len} European countries.') // Optionally print them or process further - +// --- Example: Using the helper function --- +println('\n--- Using helper function to find Japan ---') +japan := countries.find_country_by_iso('JP') or { + println('Error finding Japan: ${err}') + return +} +println('Found Japan: ${japan.str()}') diff --git a/lib/data/countries/README.md b/lib/data/countries/README.md new file mode 100644 index 00000000..cfaa02a4 --- /dev/null +++ b/lib/data/countries/README.md @@ -0,0 +1,77 @@ +# Countries Data Module + +This module provides access to country information data, including ISO codes, country names, continents, currencies, and more. It parses country data from a built-in dataset and makes it available through a simple API. + +## Purpose + +The countries module allows you to: +- Load all country data from an embedded dataset +- Search for specific countries by ISO code +- Filter countries by continent or other attributes +- Access detailed information about countries including names, codes, currencies, and more + +## Data Source + +The country data is sourced from GeoNames (http://www.geonames.org), containing information about countries including: +- ISO country codes (2-letter, 3-letter, and numeric) +- Country names and capitals +- Continent information +- Currency codes and names +- Phone country codes +- Postal code formats and regex patterns +- Languages spoken +- Neighboring countries +- FIPS codes and equivalent FIPS codes + +## Example Usage + +```v +import freeflowuniverse.herolib.data.countries + +// Get all countries +mut all_countries := countries.get_all_countries()! + +println('Total countries loaded: ${all_countries.len}') + +// Find a specific country by ISO code +japan := countries.find_country_by_iso('JP')! +println('Found Japan: ${japan.str()}') + +// Filter countries by continent +mut eu_countries := []countries.Country{} +for country in all_countries { + if country.continent == 'EU' { + eu_countries << country + } +} +println('Found ${eu_countries.len} European countries.') +``` + +## Country Structure + +Each country entry contains the following fields: + +- `iso`: ISO 2-letter country code (e.g., "BE" for Belgium) +- `iso3`: ISO 3-letter country code (e.g., "BEL" for Belgium) +- `iso_numeric`: ISO numeric country code (e.g., "056" for Belgium) +- `fips`: FIPS country code +- `country_name`: Full country name +- `capital`: Country capital city +- `area_sqkm`: Area in square kilometers +- `population`: Population count +- `continent`: Continent code (e.g., "EU" for Europe, "NA" for North America) +- `tld`: Top-level domain (e.g., ".be" for Belgium) +- `currency_code`: Currency code (e.g., "EUR" for Euro) +- `currency_name`: Full currency name +- `phone`: Phone country code +- `postal_format`: Postal code format +- `postal_regex`: Postal code validation regex +- `languages`: Languages spoken in the country +- `geonameid`: GeoNames ID +- `neighbours`: Neighboring countries (ISO codes separated by commas) +- `equiv_fips_code`: Equivalent FIPS code + +## Available Functions + +- `get_all_countries()`: Returns a list of all countries in the dataset +- `find_country_by_iso(iso_code string)`: Finds and returns a country by its 2-letter ISO code diff --git a/lib/data/countries/factory.v b/lib/data/countries/factory.v index 9355dc02..c1f48273 100644 --- a/lib/data/countries/factory.v +++ b/lib/data/countries/factory.v @@ -1,67 +1,87 @@ module countries -import os -import strings // --- Embed the data file content at compile time --- -// The path is relative to the location of this `module.v` file. -const embedded_country_data = $embed_file('data/countryInfo.txt') +// The path is relative to the location of this `factory.v` file. + // get_all_countries parses the country data embedded in the executable. // It returns a list of Country structs. pub fn get_all_countries() ![]Country { mut countries_list := []Country{} + embedded_country_data := $embed_file('data/countryInfo.txt', .zlib).to_string() + // --- Parse the embedded string --- + // Use strings.split to split the text into lines lines := embedded_country_data.split_into_lines() mut found_header := false for line in lines { // --- Skip empty lines and comments --- - if line == '' || line.trim_space().starts_with('#') { + trimmed_line := line.trim_space() + if trimmed_line == '' || trimmed_line.starts_with('#') { continue } // --- Identify and skip the header --- // Check if this line looks like the header (contains key identifiers) - if !found_header && line.contains('ISO') && line.contains('Country') && line.contains('CurrencyCode') { + if !found_header && trimmed_line.contains('ISO') && trimmed_line.contains('Country') && trimmed_line.contains('CurrencyCode') { found_header = true continue // Skip the header line itself } - // --- Process data lines --- - // Split the line by tab character - fields := line.split('\t') + // println("Processing line:${countries_list.len} ${line} ") + + // --- Process data lines --- + // Use strings.split to split the line by tab character + fields := line.split_by_space() - // Ensure we have the expected number of fields (header indicates 19) - if fields.len < 19 { - // Handle potential parsing errors or incomplete lines - // println('Warning: Skipping line with insufficient fields (found ${fields.len}): "${line}"') - continue - } // --- Create Country struct instance --- - // Map fields by index based on the header structure + // Map fields by index based on the header structure. + // Handle potential out-of-bounds or missing data gracefully using `or {}`. + // The last field might sometimes be empty or missing in the data, handle it + iso_field := fields[0] or { '' } + iso3_field := fields[1] or { '' } + iso_numeric_field := fields[2] or { '' } + fips_field := fields[3] or { '' } + country_name_field := fields[4] or { '' } + capital_field := fields[5] or { '' } + area_sqkm_field := fields[6] or { '' } + population_field := fields[7] or { '' } + continent_field := fields[8] or { '' } + tld_field := fields[9] or { '' } + currency_code_field := fields[10] or { '' } + currency_name_field := fields[11] or { '' } + phone_field := fields[12] or { '' } + postal_format_field := fields[13] or { '' } + postal_regex_field := fields[14] or { '' } + languages_field := fields[15] or { '' } + geonameid_field := fields[16] or { '' } + neighbours_field := fields[17] or { '' } + equiv_fips_code_field := fields[18] or { '' } + country := Country{ - iso: fields[0].trim_space() - iso3: fields[1].trim_space() - iso_numeric: fields[2].trim_space() - fips: fields[3].trim_space() - country_name: fields[4].trim_space() - capital: fields[5].trim_space() - area_sqkm: fields[6].trim_space() - population: fields[7].trim_space() - continent: fields[8].trim_space() - tld: fields[9].trim_space() - currency_code: fields[10].trim_space() - currency_name: fields[11].trim_space() - phone: fields[12].trim_space() - postal_format: fields[13].trim_space() - postal_regex: fields[14].trim_space() - languages: fields[15].trim_space() - geonameid: fields[16].trim_space() - neighbours: fields[17].trim_space() - equiv_fips_code: fields[18].trim_space() // Handle potential trailing empty fields or newlines + iso: iso_field.trim_space() + iso3: iso3_field.trim_space() + iso_numeric: iso_numeric_field.trim_space() + fips: fips_field.trim_space() + country_name: country_name_field.trim_space() + capital: capital_field.trim_space() + area_sqkm: area_sqkm_field.trim_space() + population: population_field.trim_space() + continent: continent_field.trim_space() + tld: tld_field.trim_space() + currency_code: currency_code_field.trim_space() + currency_name: currency_name_field.trim_space() + phone: phone_field.trim_space() + postal_format: postal_format_field.trim_space() + postal_regex: postal_regex_field.trim_space() + languages: languages_field.trim_space() + geonameid: geonameid_field.trim_space() + neighbours: neighbours_field.trim_space() + equiv_fips_code: equiv_fips_code_field.trim_space() } // --- Append to list --- @@ -70,3 +90,14 @@ pub fn get_all_countries() ![]Country { return countries_list } + +// Optional: Helper function to find a country by ISO code +pub fn find_country_by_iso(iso_code string) !Country { + countries := get_all_countries()! + for country in countries { + if country.iso == iso_code { + return country + } + } + return error('Country with ISO code "${iso_code}" not found') +} diff --git a/lib/data/countries/model.v b/lib/data/countries/model.v index 7a5b9f66..9a2c4af3 100644 --- a/lib/data/countries/model.v +++ b/lib/data/countries/model.v @@ -2,6 +2,7 @@ module countries // Country represents a country entry from countryInfo.txt pub struct Country { +pub: iso string // ISO iso3 string // ISO3 iso_numeric string // ISO-Numeric