45 Commits
Author SHA1 Message Date
phoenix 56c5aaa1d3 Adding license (#10)
clean_file Build / Check (push) Successful in 1m6s
clean_file Build / Rustfmt (push) Successful in 25s
clean_file Build / Clippy (push) Successful in 58s
clean_file Build / build (push) Successful in 1m55s
clean_file Build / Test Suite (push) Successful in 4m29s
Reviewed-on: #10
2026-07-14 11:28:25 -04:00
phoenix 235174b404 Dependency name change (#9)
clean_file Build / Check (push) Successful in 46s
clean_file Build / Rustfmt (push) Successful in 42s
clean_file Build / Test Suite (push) Successful in 1m28s
clean_file Build / build (push) Successful in 1m7s
clean_file Build / Clippy (push) Successful in 2m15s
Reviewed-on: #9
2026-07-13 12:06:24 -04:00
phoenix f837b0f5d0 Update (#8)
Rust Build / Check (push) Successful in 1m18s
Rust Build / build (push) Successful in 58s
Rust Build / Test Suite (push) Successful in 1m54s
Rust Build / Rustfmt (push) Successful in 43s
Rust Build / Clippy (push) Successful in 1m16s
clean_file pr / Check (pull_request) Successful in 38s
clean_file pr / Rustfmt (pull_request) Successful in 35s
clean_file pr / Clippy (pull_request) Successful in 58s
Reviewed-on: #8
2026-06-14 18:08:36 -04:00
phoenix 79a3e47a1b Update deps (#7)
Rust Build / Check (push) Successful in 1m2s
Rust Build / Rustfmt (push) Successful in 36s
Rust Build / Test Suite (push) Successful in 1m23s
Rust Build / build (push) Successful in 52s
Rust Build / Clippy (push) Successful in 42s
Reviewed-on: #7
2026-06-13 13:09:55 -04:00
phoenix d8cb2cee19 Update dependencies (#6)
Rust Build / Check (push) Successful in 31s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Test Suite (push) Successful in 1m3s
Rust Build / build (push) Successful in 1m1s
Rust Build / Clippy (push) Successful in 41s
Reviewed-on: #6
2026-06-07 15:33:57 -04:00
phoenix 7d9142dc13 Merge pull request 'v1.0' (#1) from v1.x into main
Rust Build / Check (push) Successful in 26s
Rust Build / Test Suite (push) Successful in 47s
Rust Build / Rustfmt (push) Successful in 33s
Rust Build / build (push) Successful in 29s
Rust Build / Clippy (push) Successful in 47s
Rust Build / Check (pull_request) Successful in 1m17s
Rust Build / Rustfmt (pull_request) Successful in 30s
Rust Build / Clippy (pull_request) Successful in 40s
Rust Build / Test Suite (pull_request) Successful in 2m4s
Rust Build / build (pull_request) Successful in 58s
Reviewed-on: #1
2026-06-06 14:12:01 -04:00
phoenix f9339ae9a1 bump: clean_file
Rust Build / Check (pull_request) Successful in 33s
Rust Build / Test Suite (pull_request) Successful in 37s
Rust Build / Rustfmt (pull_request) Successful in 45s
Rust Build / Clippy (pull_request) Successful in 27s
Rust Build / build (pull_request) Successful in 1m13s
2026-06-06 14:08:18 -04:00
phoenix a0bf202b39 Workflow branch update
Rust Build / Check (pull_request) Successful in 26s
Rust Build / Test Suite (pull_request) Successful in 38s
Rust Build / Rustfmt (pull_request) Successful in 50s
Rust Build / Clippy (pull_request) Successful in 28s
Rust Build / build (pull_request) Successful in 45s
2026-06-06 14:07:23 -04:00
phoenix f5cb2ed892 Add tests (#5)
Rust Build / Check (push) Successful in 33s
Rust Build / Rustfmt (push) Successful in 35s
Rust Build / Test Suite (push) Successful in 38s
Rust Build / Clippy (push) Successful in 29s
Rust Build / build (push) Successful in 42s
Reviewed-on: #5
2026-06-06 14:03:42 -04:00
phoenix cd0ea8a387 Migrate (#4)
Rust Build / Clippy (push) Successful in 33s
Rust Build / Check (push) Successful in 26s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Test Suite (push) Successful in 47s
Rust Build / build (push) Successful in 30s
Reviewed-on: #4
2026-06-06 12:48:58 -04:00
phoenix e7f6ddec9a Adding rust files (#3)
Rust Build / Check (push) Successful in 38s
Rust Build / Rustfmt (push) Successful in 35s
Rust Build / Test Suite (push) Successful in 38s
Rust Build / Clippy (push) Successful in 37s
Rust Build / build (push) Successful in 42s
Reviewed-on: #3
2026-06-05 18:49:53 -04:00
phoenix 9ec9fa1516 Clear out (#2)
Reviewed-on: #2
2026-06-05 18:06:38 -04:00
phoenixandphoenix f2a650ef27 go version bump (#21)
Go / build (pull_request) Failing after 7s
Reviewed-on: #21
Co-authored-by: phoenix <mail@kundeng.us>
Co-committed-by: phoenix <mail@kundeng.us>
2026-05-03 16:15:12 -04:00
phoenixandphoenix c391939960 Update go (#20)
Reviewed-on: #20
Co-authored-by: phoenix <mail@kundeng.us>
Co-committed-by: phoenix <mail@kundeng.us>
2026-04-04 21:35:07 -04:00
phoenixandphoenix 340c90211f Package update (#19)
Reviewed-on: #19
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-12-26 21:31:04 +00:00
phoenixandphoenix e737280a3c Removed workflow file (#18)
Reviewed-on: #18
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-27 02:13:44 +00:00
phoenixandphoenix 18d1d2730f Refactoring (#17)
Reviewed-on: #17
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-27 02:10:51 +00:00
phoenixandphoenix fc1f3fa814 tsk-15: Update go version (#16)
Closes #15

Reviewed-on: #16
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-24 20:00:26 +00:00
phoenixandphoenix 3151405d32 Some major changes (#14)
Reviewed-on: #14
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-16 00:44:55 +00:00
phoenixandphoenix 154c9f493e print version (#13)
Reviewed-on: #13
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-27 23:55:39 +00:00
phoenixandphoenix 7e3fff50c1 golang version bump (#12)
Reviewed-on: #12
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-27 23:22:56 +00:00
phoenix 27d76c1c51 Go migration (#5)
Reviewed-on: #5
2025-09-01 22:14:19 +00:00
phoenixandphoenix 4a109467e3 add versioning (#11)
Reviewed-on: #11
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-09-01 22:13:29 +00:00
phoenixandphoenix 71c99cdb50 Update go (#10)
Reviewed-on: #10
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-09-01 21:54:32 +00:00
phoenixandphoenix 2c0a662733 Parser (#9)
Reviewed-on: #9
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-09-01 21:50:00 +00:00
phoenixandphoenix 6f9029d4e3 main code (#8)
Reviewed-on: #8
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-28 21:28:37 +00:00
phoenixandphoenix 75dd476d71 Initial go code (#7)
Reviewed-on: #7
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-27 19:36:32 +00:00
phoenixandphoenix c930c146e5 Remove rust code (#6)
Reviewed-on: #6
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-27 19:27:02 +00:00
phoenixandphoenix 903ada907f Version bump (#4)
Reviewed-on: #4
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:38:32 +00:00
phoenixandphoenix 2c916856e9 Update dependencies (#3)
Reviewed-on: #3
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:34:54 +00:00
phoenixandphoenix 42e39df59f Add readme (#2)
Reviewed-on: #2
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:31:50 +00:00
phoenixandphoenix 49842756ba Rust std change (#1)
Reviewed-on: #1
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:26:05 +00:00
KD 6743a808b9 Merge branch 'version_bump' into 'main'
Version bump

See merge request kdeng00/clean_file!4
2025-03-09 18:56:00 +00:00
KD b2116332ed Version bump 2025-03-09 18:56:00 +00:00
KD ad3c350707 Merge branch 'ver_up' into 'main'
Updating rust edition

See merge request kdeng00/clean_file!3
2025-03-09 03:10:00 +00:00
phoenix f4937514dd Updating rust edition 2025-03-08 22:08:20 -05:00
KD 04f0c03db7 Merge branch 'ci' into 'main'
Added workflow file

See merge request kdeng00/clean_file!1
2025-03-09 03:06:12 +00:00
phoenix c810a85da0 Added workflow file 2025-03-08 22:02:33 -05:00
phoenixandphoenix 936f07ad01 Updated serde and serde_json (#1)
Reviewed-on: #1
Co-authored-by: phoenix <kundeng94@gmail.com>
Co-committed-by: phoenix <kundeng94@gmail.com>
2025-02-10 02:23:36 +00:00
phoenix 156ab957fd Update .github/workflows/rust.yaml 2025-02-03 00:32:53 +00:00
phoenix ef6eba61a7 Update .github/workflows/rust.yaml 2025-02-03 00:32:31 +00:00
phoenix 59a5e1f678 Update .github/workflows/rust.yaml 2025-02-03 00:31:44 +00:00
phoenix e240276db7 Update .github/workflows/rust.yaml 2025-02-03 00:31:23 +00:00
phoenix c4f27e924d Update .github/workflows/rust.yaml 2025-02-03 00:29:11 +00:00
phoenix 42fc92925d Add .github/workflows/rust.yaml 2025-02-03 00:27:12 +00:00
13 changed files with 2418 additions and 246 deletions
+65
View File
@@ -0,0 +1,65 @@
name: clean_file pr
on:
pull_request:
branches:
- main
jobs:
check:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo check
fmt:
name: Rustfmt
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo clippy -- -D warnings
+103
View File
@@ -0,0 +1,103 @@
name: clean_file Build
on:
push:
branches:
- main
jobs:
check:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo check
test:
name: Test Suite
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo test
fmt:
name: Rustfmt
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo clippy -- -D warnings
build:
name: build
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo build --release
+2 -1
View File
@@ -1 +1,2 @@
/target target/
numbers.json
View File
Generated
+1899
View File
File diff suppressed because it is too large Load Diff
+10 -5
View File
@@ -1,10 +1,15 @@
[package] [package]
name = "clean_file" name = "clean_file"
version = "0.2.0" version = "1.1.1"
edition = "2021" edition = "2024"
license = "MIT"
description = "A tool to sanitize US phone numbers"
rust-version = "1.96"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
serde = { version = "1.0.203", features = ["derive"] } tokio = { version = "1.52.3", features = ["full"] }
serde_json = "1.0.117" serde_json = { version = "1.0.150" }
schedtxt_models = { git = "ssh://git@git.kundeng.us/phoenix/schedtxt_models.git", tag = "v0.5.3", features = ["contact"] }
[dev-dependencies]
+22
View File
@@ -0,0 +1,22 @@
Copyright (c) 2026 Kun Deng.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
+3
View File
@@ -0,0 +1,3 @@
# clean_file
A CLI tool to sanitize a phone numbers. Takes unformatted US phone numbers and
standardizes them.
+21 -28
View File
@@ -1,39 +1,32 @@
use std::env; pub mod parser;
pub mod version;
mod parser;
fn main() {
let args: Vec<String> = env::args().collect();
#[tokio::main]
async fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 { if args.len() < 2 {
println!("Provide path to file"); println!("Invalid arguments provided");
return; std::process::exit(-1);
} }
let filepath: &String = args.get(1).unwrap(); if version::contains_version(&args) {
version::print_version();
std::process::exit(-1);
}
println!("Filepath is: {:?}", filepath); let filepath = &args[1];
println!("Filepath: {filepath:?}");
let myparser = parser::parser::NumberParser { let prsr = parser::NumberParser {
filepath: filepath.clone(), filepath: filepath.clone(),
}; };
let rawvalues = myparser.filedump(); match prsr.file_dump().await {
Ok(contacts) => {
let parsed_values = myparser.updatevalues(&rawvalues); prsr.print_phone_numbers(&contacts);
prsr.save_file(contacts, parser::DEFAULT_OUTPUT_FILE).await;
let newupdated = myparser.removedups(&parsed_values);
myparser.print_values(&newupdated, true);
let result = myparser.save_file(parsed_values);
match result {
Ok(o) => {
println!("Successfully saved file: {:?}", o);
} }
Err(er) => { Err(err) => {
println!("Error saving file: {:?}", er); eprintln!("Error: {err:?}");
} }
} };
} }
-212
View File
@@ -1,212 +0,0 @@
pub mod parser {
use std::collections::HashSet;
use std::fs::File;
use std::io::prelude::*;
use std::io::{BufRead, BufReader};
use serde::Deserialize;
use serde::Serialize;
#[derive(Clone, Deserialize, Serialize)]
pub struct SomeObject {
pub value: String,
}
pub struct NumberParser {
pub filepath: String,
}
impl NumberParser {
pub fn filedump(&self) -> Vec<SomeObject> {
println!("\nDumping files");
let mut objs: Vec<SomeObject> = Vec::new();
if let Ok(lines) = self.read_lines(&self.filepath) {
for line in lines {
if let Ok(phonenumber) = line {
let contains_letters = phonenumber.chars().any(|c| c.is_alphabetic());
if contains_letters {
continue;
}
let myobj: SomeObject = SomeObject { value: phonenumber };
if !myobj.value.is_empty() {
objs.push(myobj);
}
}
}
}
return objs;
}
pub fn updatevalues(&self, vals: &Vec<SomeObject>) -> Vec<SomeObject> {
println!("\nUpdating values");
let mut updated: Vec<SomeObject> = Vec::new();
for a in vals {
let mut parsed: String = a.value.clone();
if a.value.len() < 2 {
println!("{} is an invalid number", a.value);
continue;
}
let pars = self.remove_some_data(&parsed);
parsed.clear();
parsed = pars;
println!("{}", parsed.clone());
let updated_parsed = self.add_prefix(parsed);
let myobj: SomeObject = SomeObject {
value: updated_parsed.clone(),
};
updated.push(myobj);
}
return updated;
}
pub fn removedups(&self, vals: &Vec<SomeObject>) -> Vec<SomeObject> {
println!("\nRemoving duplicates");
let mut tmp: HashSet<String> = HashSet::new();
let mut mm: Vec<SomeObject> = Vec::new();
mm.clone_from(vals);
mm.retain(|e| tmp.insert(e.value.clone()));
let mut updated: Vec<SomeObject> = Vec::new();
for t in tmp {
let so: SomeObject = SomeObject { value: t.clone() };
updated.push(so);
}
return updated;
}
pub fn print_values(&self, vals: &Vec<SomeObject>, print_total: bool) {
println!("\nPrinting values");
for o in vals {
println!("Value: {}", o.value);
}
if print_total {
println!("\nTotal numbers: {:?}", vals.len());
}
}
pub fn save_file(&self, vals: Vec<SomeObject>) -> std::io::Result<()> {
println!("\nSaving file");
let filename: String = String::from("numbers.json");
let mut all_numbers: Vec<String> = Vec::new();
for val in &vals {
all_numbers.push(val.value.clone());
}
let json = serde_json::to_string_pretty(&all_numbers).unwrap();
let mut file = File::create(filename)?;
file.write_all(json.as_bytes())?;
Ok(())
}
fn read_lines(&self, filename: &str) -> std::io::Result<std::io::Lines<BufReader<File>>> {
let file = File::open(filename)?;
Ok(BufReader::new(file).lines())
}
fn remove_some_data(&self, unparsed: &String) -> String {
println!("Unparsed: {}", unparsed);
let mut parsed: String = String::new();
let mychars = unparsed.chars();
for i in 0..unparsed.len() {
let mychar_wrap = mychars.clone().nth(i);
if let None = mychar_wrap {
continue;
}
let mychar = mychar_wrap.unwrap();
if mychar.is_numeric() {
parsed.push(mychar.clone());
}
}
println!("Parsed: {}", parsed);
return parsed;
}
fn add_prefix(&self, raw: String) -> String {
let mut mychars = raw.chars().clone();
let first_char: char = mychars.nth(0).clone().unwrap();
let second_char: char = mychars.nth(1).clone().unwrap();
let mut parsed: String = raw.clone();
if first_char == '1' {
parsed.insert(0, '+');
} else if first_char != '+' {
if second_char != '1' {
parsed.insert(0, '+');
parsed.insert(1, '1');
} else {
parsed.insert(0, '+');
parsed.insert(1, '1');
}
}
return parsed;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn removing_text() {
let sometext: String = String::from("a1234567890");
let numberparser = NumberParser {
filepath: String::new(),
};
let removetext = numberparser.remove_some_data(&sometext);
let mut result = true;
for i in 0..removetext.len() {
let c = removetext.chars().nth(i).unwrap();
if !c.is_numeric() {
result = false;
break;
}
}
assert_eq!(result, true);
}
#[test]
fn adding_prefix() {
let sometext: String = String::from("1234567890");
let numberparser = NumberParser {
filepath: String::new(),
};
let modified = numberparser.add_prefix(sometext);
let chars = modified.chars().clone();
let firstcharcheck: char = chars.clone().nth(0).unwrap();
let secondcharcheck: char = chars.clone().nth(1).unwrap();
assert_eq!(firstcharcheck, '+');
assert_eq!(secondcharcheck, '1');
}
}
}
+263
View File
@@ -0,0 +1,263 @@
use std::io::BufRead;
pub const DEFAULT_OUTPUT_FILE: &str = "numbers.json";
const LETTERS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
#[derive(Clone, Debug, Default)]
pub struct NumberParser {
pub filepath: String,
}
impl NumberParser {
pub async fn file_dump(
&self,
) -> Result<Vec<schedtxt_models::contact::Contact>, std::io::Error> {
println!("Dumping files");
let mut objs: Vec<schedtxt_models::contact::Contact> = Vec::new();
match self.read_lines(&self.filepath).await {
Ok(lines) => {
for line in lines {
let contains_letters = line.chars().any(|c| LETTERS.contains(c));
if contains_letters {
continue;
} else {
let my_obj = schedtxt_models::contact::Contact {
phone_number: line.clone(),
..Default::default()
};
if !my_obj.phone_number.is_empty() {
objs.push(my_obj);
}
}
}
let updated_contacts = self.update_contacts(&objs).await;
let removed_duplicates = self.remove_dups(&updated_contacts).await;
Ok(removed_duplicates)
}
Err(err) => Err(err),
}
}
pub async fn save_file(&self, numbers: Vec<schedtxt_models::contact::Contact>, filename: &str) {
match serde_json::to_string(&numbers) {
Ok(json_string) => match std::fs::write(filename, json_string) {
Ok(_) => {
println!("Saved to: {filename:?}");
}
Err(err) => {
eprintln!("Error: {err:?}");
}
},
Err(err) => {
eprintln!("Error: {err:?}");
}
};
}
pub fn print_phone_numbers(&self, contacts: &Vec<schedtxt_models::contact::Contact>) {
println!("Printing phone numbers");
for contact in contacts {
println!("Phone Number: {:?}", contact.phone_number);
}
println!("Total phone numbers: {:?}", contacts.len());
}
async fn read_lines(&self, filename: &String) -> Result<Vec<String>, std::io::Error> {
match std::fs::File::open(filename) {
Ok(file) => {
let reader = std::io::BufReader::new(file);
reader.lines().collect()
}
Err(err) => Err(err),
}
}
async fn remove_dups(
&self,
contacts: &Vec<schedtxt_models::contact::Contact>,
) -> Vec<schedtxt_models::contact::Contact> {
let mut unique_contacts: Vec<schedtxt_models::contact::Contact> = Vec::new();
let mut unique_items = std::collections::HashSet::new();
for val in contacts {
unique_items.insert(val.phone_number.clone());
}
for unique_item in unique_items {
let contact = schedtxt_models::contact::Contact {
phone_number: unique_item,
..Default::default()
};
unique_contacts.push(contact);
}
unique_contacts
}
async fn update_contacts(
&self,
contacts: &Vec<schedtxt_models::contact::Contact>,
) -> Vec<schedtxt_models::contact::Contact> {
let mut updated: Vec<schedtxt_models::contact::Contact> = Vec::new();
for ct in contacts {
let phone_number = ct.phone_number.clone();
if phone_number.len() < 2 {
println!("Invalid number: {phone_number:?}");
continue;
}
let pars = self.remove_some_data(&phone_number).await;
match self.add_prefix(&pars) {
Ok(updated_parsed) => {
let contact = schedtxt_models::contact::Contact {
phone_number: updated_parsed,
..Default::default()
};
updated.push(contact);
}
Err(err) => {
eprintln!("Error: {err:?}");
std::process::exit(-2);
}
};
}
updated
}
fn add_prefix(&self, raw: &String) -> Result<String, std::io::Error> {
if raw.is_empty() {
Err(std::io::Error::other("Empty"))
} else {
let mut parsed: String = String::new();
let first_char = raw.chars().nth(0).unwrap();
if first_char == '1' {
parsed = format!("+{raw}");
} else if first_char != '+' {
parsed = format!("+1{raw}");
}
Ok(parsed)
}
}
async fn remove_some_data(&self, unparsed: &str) -> String {
let mut parsed: String = String::new();
for ch in unparsed.chars() {
if ch == ' ' {
continue;
} else {
if ch.is_numeric() {
parsed.push(ch);
}
}
}
parsed
}
}
#[cfg(test)]
mod tests {
use schedtxt_models::contact::Contact;
const TEST_NUMBERS_0: &str = "tests/numbers-0.txt";
#[tokio::test]
async fn test_file_dump() {
let file_exists = {
let path = std::path::Path::new(TEST_NUMBERS_0);
path.exists()
};
assert_eq!(true, file_exists, "File does not exists {TEST_NUMBERS_0:?}");
let filename = String::from(TEST_NUMBERS_0);
let prsr = super::NumberParser { filepath: filename };
let original: Vec<Contact> = vec![
Contact {
phone_number: String::from("+13055550112"),
..Default::default()
},
Contact {
phone_number: String::from("+13175550123"),
..Default::default()
},
Contact {
phone_number: String::from("+14155550135"),
..Default::default()
},
Contact {
phone_number: String::from("+16085550190"),
..Default::default()
},
Contact {
phone_number: String::from("+17135550167"),
..Default::default()
},
Contact {
phone_number: String::from("+16025550177"),
..Default::default()
},
Contact {
phone_number: String::from("+13605550158"),
..Default::default()
},
Contact {
phone_number: String::from("+12175550194"),
..Default::default()
},
];
match prsr.file_dump().await {
Ok(contacts) => {
assert!((contacts.len() > 0), "No contacts has been parsed");
let phone_numbers_1: std::collections::HashSet<_> =
contacts.iter().map(|p| p.phone_number.clone()).collect();
let phone_numbers_2: std::collections::HashSet<_> =
original.iter().map(|p| p.phone_number.clone()).collect();
assert_eq!(phone_numbers_1, phone_numbers_2, "No match");
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
};
}
#[tokio::test]
async fn test_save_file() {
let prsr = super::NumberParser {
filepath: String::from(TEST_NUMBERS_0),
};
let results = prsr.file_dump().await;
assert!(results.is_ok(), "File dump not successful");
let test_output_file: &str = "test-numbers.json";
let contacts = results.unwrap();
prsr.save_file(contacts, test_output_file).await;
let file_exists = {
let path = std::path::Path::new(test_output_file);
path.exists()
};
assert!(file_exists, "Contacts were not saved");
match std::fs::remove_file(test_output_file) {
Ok(_) => {
println!("File removed");
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
}
}
}
+20
View File
@@ -0,0 +1,20 @@
pub fn print_version() {
let name = env!("CARGO_PKG_NAME");
let version = env!("CARGO_PKG_VERSION");
println!("{name:?} {version:?}");
}
pub fn contains_version(args: &Vec<String>) -> bool {
let valid_flags = vec!["-v", "--version"];
for arg in args {
for valid_flag in &valid_flags {
if valid_flag == arg {
return true;
}
}
}
false
}
+10
View File
@@ -0,0 +1,10 @@
(217) 555-0194
(602) 555-0177
(713) 555-0167
(608) 555-0190
(305) 555-0112
(415) 555-0135
(608) 555-0190
(602) 555-0177
(317) 555-0123
(360) 555-0158