12 Commits
Author SHA1 Message Date
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
14 changed files with 411 additions and 300 deletions
+46
View File
@@ -0,0 +1,46 @@
name: Go
on:
push:
branches: [ main, go_migr ]
pull_request:
branches: [ main, go_migr ]
jobs:
build:
runs-on: ubuntu-24.04 # You can change this to macos-latest or windows-latest if needed
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '1.24.6' # You can specify a specific version or 'stable'
- name: Build
run: |
go build -v -ldflags "\
-X main.version=${{ github.ref_name }} \
-X main.commit=${{ github.sha }} \
-X main.date=$(date +%Y-%m-%dT%H:%M:%S%z)" \
-o clean_file
- name: Test
run: go test -v ./...
- name: Run gofmt (optional)
# Uncomment to check code formatting with gofmt
run: |
if [ -n "$(gofmt -l.)" ]; then
echo "Go code is not formatted. Please run 'gofmt -w.' to fix it."
exit 1
fi
- name: Run golint (optional)
# Uncomment to check code style with golint
run: |
if [ -n "$(golint./...)" ]; then
echo "Go code has style issues. Please run 'golint./...' to see them."
exit 1
fi
-37
View File
@@ -1,37 +0,0 @@
name: Rust
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
env:
# Customize the profile here (e.g., release, debug)
PROFILE: release
jobs:
build:
runs-on: ubuntu-latest # Only target ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --release # Or --debug, depending on the env.PROFILE
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --release # Or --debug, depending on the env.PROFILE
+2 -1
View File
@@ -1 +1,2 @@
/target
/clean_file
numbers.json
View File
-11
View File
@@ -1,11 +0,0 @@
[package]
name = "clean_file"
description = "Software tool that sanitizes a list of phone numbers"
version = "0.3.0"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0.218", features = ["derive"] }
serde_json = "1.0.140"
+13
View File
@@ -0,0 +1,13 @@
CLI software that processes a text file containing US phone numbers
and sanitizes the numbers. The result is contained in a json file.
## Building
```
go build
```
To include version information
```
go build -ldflags "-X main.version=3.0.101 -X main.commit=$(git rev-parse HEAD) -X main.date=$(date +%Y-%m-%dT%H:%M:%S%z)" -o clean_file
```
+3
View File
@@ -0,0 +1,3 @@
module git.kundeng.us/phoenix/clean_file
go 1.25.3
+28
View File
@@ -0,0 +1,28 @@
package main
import "fmt"
import "os"
import "git.kundeng.us/phoenix/clean_file/parser"
func main() {
fmt.Println("clean_file")
args := os.Args
if len(args) < 2 {
fmt.Println("Invalid arguments provided")
os.Exit(-1)
}
filepath := args[1]
fmt.Println("File path:", filepath)
prsr := parser.NumberParser{FilePath: filepath}
rawValues := prsr.FileDump()
parsedValues := prsr.UpdateValues(rawValues)
newUpdated := prsr.RemoveDups(parsedValues)
prsr.PrintValues(newUpdated, true)
prsr.SaveFile(newUpdated)
}
+173
View File
@@ -0,0 +1,173 @@
package parser
import "fmt"
import "os"
import "unicode"
import (
"bufio"
"log"
)
import "encoding/json"
import "strings"
const Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
type SomeObject struct {
Value string `json:"value"`
}
type NumberParser struct {
FilePath string
}
func (prsr NumberParser) FileDump() []SomeObject {
fmt.Println("Dumping files")
objs := []SomeObject{}
for _, line := range prsr.readLines(prsr.FilePath) {
if strings.ContainsAny(line, Letters) {
continue
}
myObj := SomeObject{Value: line}
if myObj.Value != "" {
objs = append(objs, myObj)
}
}
return objs
}
func (prsr NumberParser) UpdateValues(vals []SomeObject) []SomeObject {
updated := []SomeObject{}
for _, val := range vals {
parsed := val.Value
if len(parsed) < 2 {
fmt.Println("Invalid number:", parsed)
continue
}
pars := prsr.removeSomeData(parsed)
parsed = pars
fmt.Println(parsed)
updatedParsed := prsr.addPrefix(parsed)
updated = append(updated, SomeObject{Value: updatedParsed})
}
return updated
}
func (prsr NumberParser) RemoveDups(vals []SomeObject) []SomeObject {
updated := []SomeObject{}
uniqueItems := make(map[string]string)
for _, val := range vals {
uniqueItems[val.Value] = val.Value
}
for _, item := range uniqueItems {
updated = append(updated, SomeObject{Value: item})
}
return updated
}
func (prsr NumberParser) PrintValues(vals []SomeObject, printTotal bool) {
fmt.Println("Printing values")
for _, val := range vals {
fmt.Println("Value:", val.Value)
}
if printTotal {
fmt.Println("Total Numbers:", len(vals))
}
}
func (prsr NumberParser) SaveFile(vals []SomeObject) {
filename := "numbers.json"
allNumbers := []string{}
for _, val := range vals {
allNumbers = append(allNumbers, val.Value)
}
// Create json and save it to the filesystem
jsonData, err := json.MarshalIndent(allNumbers, "", " ")
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return
}
err = os.WriteFile(filename, jsonData, 0644)
if err != nil {
fmt.Println("Error writing file:", err)
return
}
}
func (prsr NumberParser) readLines(filename string) []string {
// Open the file
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Create a scanner to read the file line by line
scanner := bufio.NewScanner(file)
lines := []string{}
// Read line by line
for scanner.Scan() {
line := scanner.Text()
lines = append(lines, line)
}
// Check for any errors during scanning
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
return lines
}
func (prsr NumberParser) removeSomeData(unparsed string) string {
parsed := ""
for _, ch := range unparsed {
if ch == ' ' {
continue
} else {
if unicode.IsDigit(ch) {
parsed += string(ch)
}
}
}
fmt.Println("Parsed:", parsed)
return parsed
}
func (prsr NumberParser) addPrefix(raw string) string {
parsed := raw
firstChar := raw[0]
secondChar := raw[1]
if firstChar == '1' {
parsed = "+" + parsed
} else if firstChar != '+' {
if secondChar != '1' {
parsed = "+1" + parsed
} else {
parsed = "+1" + parsed
}
}
return parsed
}
+129
View File
@@ -0,0 +1,129 @@
package parser
import "testing"
import "fmt"
const Test_File_Path = "../tests/numbers.txt"
// Add three tests
// File dump
func Test_FileDump(t *testing.T) {
parser := NumberParser{FilePath: Test_File_Path}
rawValues := parser.FileDump()
testValues := []SomeObject{
{Value: "(217) 555-0194"},
{Value: "(602) 555-0177"},
{Value: "(713) 555-0167"},
{Value: "(608) 555-0190"},
{Value: "(305) 555-0112"},
{Value: "(415) 555-0135"},
{Value: "(608) 555-0190"},
{Value: "(602) 555-0177"},
{Value: "(317) 555-0123"},
{Value: "(360) 555-0158"},
}
if len(rawValues) < 1 {
t.Error("Dump should not be empty")
}
if !dataEqual(rawValues, testValues) {
t.Error("File dump was not correctly dump")
}
}
// Parse values
func Test_Parsed(t *testing.T) {
parser := NumberParser{FilePath: Test_File_Path}
rawValues := parser.FileDump()
if len(rawValues) < 1 {
t.Error("Dump should not be empty")
}
parsed := parser.UpdateValues(rawValues)
testValues := []SomeObject{
{Value: "+12175550194"},
{Value: "+16025550177"},
{Value: "+17135550167"},
{Value: "+16085550190"},
{Value: "+13055550112"},
{Value: "+14155550135"},
{Value: "+16085550190"},
{Value: "+16025550177"},
{Value: "+13175550123"},
{Value: "+13605550158"},
}
aSize := len(parsed)
bSize := len(testValues)
if aSize != bSize {
t.Error("Data has varrying sizes A", aSize, " B", bSize)
}
if !dataEqual(parsed, testValues) {
t.Error("Data has not be updated")
}
}
// Remove duplicates
func Test_RemoveDups(t *testing.T) {
parser := NumberParser{FilePath: Test_File_Path}
rawValues := parser.FileDump()
if len(rawValues) < 1 {
t.Error("Dump should not be empty")
}
parsed := parser.UpdateValues(rawValues)
finalAmount := parser.RemoveDups(parsed)
testValues := []SomeObject{
{Value: "+12175550194"},
{Value: "+16025550177"},
{Value: "+17135550167"},
{Value: "+16085550190"},
{Value: "+13055550112"},
{Value: "+14155550135"},
{Value: "+13175550123"},
{Value: "+13605550158"},
}
aSize := len(finalAmount)
bSize := len(testValues)
if aSize != bSize {
t.Error("Data has varrying sizes A", aSize, " B", bSize)
}
if !dataEqual(finalAmount, testValues) {
fmt.Println("Printing final amount")
for _, val := range finalAmount {
fmt.Println("Value:", val.Value)
}
fmt.Println("Printing test values")
for _, val := range testValues {
fmt.Println("Value:", val.Value)
}
t.Error("Data has not be updated")
}
}
func dataEqual(a, b []SomeObject) bool {
if len(a) != len(b) {
return false
}
for i := range a {
foundIt := false
for j := range b {
if a[i] == b[j] {
foundIt = true
}
}
if !foundIt {
return false
}
}
return true
}
-39
View File
@@ -1,39 +0,0 @@
use std::env;
mod parser;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Provide path to file");
return;
}
let filepath: &String = args.get(1).unwrap();
println!("Filepath is: {:?}", filepath);
let myparser = parser::parser::NumberParser {
filepath: filepath.clone(),
};
let rawvalues = myparser.filedump();
let parsed_values = myparser.updatevalues(&rawvalues);
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) => {
println!("Error saving file: {:?}", er);
}
}
}
-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');
}
}
}
+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
+7
View File
@@ -0,0 +1,7 @@
package version
var (
Version = "dev"
Commit = "none"
Date = "unknown"
)