Compare commits

...

96 Commits
v0.1.2 ... main

Author SHA1 Message Date
John Zacarias Jekel 0179a99a32 Optimizations and cleanup 1 year ago
John Zacarias Jekel 1dabce5224 An even further performance improvement: we are no longer attempting to support words without vowels 1 year ago
John Zacarias Jekel e48f584262 More performance improvements 1 year ago
John Jekel 4e28518ab3 More progress with new implementation 1 year ago
John Zacarias Jekel 3d4dbf1ae4 Continue improving the new rewrite's efficiency 1 year ago
John Zacarias Jekel 8e676b449d Begin a new rewrite that has more efficient loops 1 year ago
John Zacarias Jekel 1c1df67d64 Begin rewriting translation function to be more efficient 1 year ago
John Zacarias Jekel 10af4bd813 Increment minor version number, remove translate_strings.rs and other old code 1 year ago
John Zacarias Jekel ee2eef8b25 Add missing benches fro byte_string.rs 1 year ago
John Zacarias Jekel 21225aa4bc Finish docs for byte_string.rs 1 year ago
John Zacarias Jekel a97120228a Minor performance optimization 1 year ago
John Jekel 406484b45e Last doc progress before bed 1 year ago
John Jekel 22c7944a7d Work on docs for byte_string.rs 1 year ago
John Zacarias Jekel a7866e648c Begin working on docs for byte_string.rs 1 year ago
John Zacarias Jekel 796543722a Fix benches 1 year ago
John Jekel 80fa163ce4 Performance optimizations 1 year ago
John Jekel edcde04247 Add comments 1 year ago
John Jekel 1d83496e8a Use extend_from_slice which is more efficient 1 year ago
John Jekel c9663b9e14 Add a reminder for myself to not forget to add integration tests 1 year ago
John Jekel a425325fe6 Improve docs; also improve efficiency in string.rs 1 year ago
John Zacarias Jekel b9d341553b More progress 1 year ago
John Zacarias Jekel 47cbf3aba0 Move translate_word.rs to byte_string.rs 1 year ago
John Zacarias Jekel 92d817489d helpers.rs in now fully moved to byte_string.rs 1 year ago
John Zacarias Jekel c37d6a1b94 Move more things to byte_string.rs 1 year ago
John Zacarias Jekel 197fd51228 Even more cleanup 1 year ago
John Zacarias Jekel c046d15723 More restructuring 1 year ago
John Zacarias Jekel dc6bb6a0d0 Begin re-restructuring 1 year ago
John Zacarias Jekel d03c413ee7 More ASCII progress 1 year ago
John Zacarias Jekel 2d2333677c Begin restructuring/seperating ascii from utf8 1 year ago
John Zacarias Jekel 2be7ede4ee Seperate nightly-features into subfeatures 1 year ago
John Zacarias Jekel 97cc72fc47 Very minor performance benefit from generics 1 year ago
John Zacarias Jekel bc05413834 Add a generic UTF-8 regular translate function, and use it to power other functions when nightly-features is enabled 1 year ago
John Zacarias Jekel e535a69ac3 Add generic function for UTF-8 word translation 1 year ago
John Zacarias Jekel 4d9a89dec2 Add another helper function 1 year ago
John Zacarias Jekel 9ebeb071da Experiment with const generics 1 year ago
John Zacarias Jekel e232c34202 Minor improvements 1 year ago
John Zacarias Jekel 0684da4741 Now ascii functions use Vec<u8> internally and convert as needed for higher speed 1 year ago
John Zacarias Jekel efbcba6080 Begin transitioning ascii functions (at least internally) to Vec<u8> for greater speed 1 year ago
John Zacarias Jekel 39bdc0eb62 ASCII performance improvements 1 year ago
John Zacarias Jekel 1c0c52a975 Minor improvements 1 year ago
John Zacarias Jekel caf6bdee78 Increment minor version number to 4 1 year ago
John Zacarias Jekel e4e898847d Minor doc tweaks 1 year ago
John Zacarias Jekel 9b8688271a Finish documentation for translate_strings.rs 1 year ago
John Zacarias Jekel 3ebceaff28 Begin properly documenting ascii functions 1 year ago
John Jekel 107efc314e Add tests for is_uppercase 1 year ago
John Zacarias Jekel 870512da4f Add more benches for the main translation functions 1 year ago
John Zacarias Jekel 3b7e6b85a8 Improve benches for the word functions 1 year ago
John Zacarias Jekel 46b24494e8 Nevermind, it was a bug in the test 1 year ago
John Zacarias Jekel a0417566ed Oops, looks like there is still uppercase bugs 1 year ago
John Zacarias Jekel 13a36fc15b Speedup word_is_uppercase_ascii 1 year ago
John Zacarias Jekel d898f44220 Improve efficiency of is_y and is_vowel 1 year ago
John Zacarias Jekel 37c4b0fac0 Improve documentation more 1 year ago
John Zacarias Jekel 2f2e6d782b Improve tests and documentation more 1 year ago
John Zacarias Jekel a55ae8c857 Improve documentation 1 year ago
John Zacarias Jekel a989f9eb31 Ascii version of functions now working too! 1 year ago
John Zacarias Jekel e563d24d65 All tests pass now, though the _ascii versions of functions still need fixes 1 year ago
John Zacarias Jekel 77a7b190a0 Handle uppercase words in translate_words_with_style properly now 1 year ago
John Zacarias Jekel 992aa61afd Restructure things to support dealing with all uppercase words 1 year ago
John Zacarias Jekel 1bc7b19916 Move anslatetray-benchmark-file into the anslatortray binary 1 year ago
John Zacarias Jekel eccd70b586 Merge remote-tracking branch 'refs/remotes/origin/main' 1 year ago
John Zacarias Jekel b49c43c6ee Switch from multiple programs to one anslatortray binary 1 year ago
John Jekel d557d80a20 Add the anslatetray-benchmark-file program 1 year ago
John Zacarias Jekel 15f5a3f979 Switch philosophy so that the utf8 safe version of functions is the default, and the ASCII-only versions are opt-in 1 year ago
John Zacarias Jekel da98dc30cd Begin to make the distinction between UTF8 safe and unsafe functions, and implement optimizations when we know the text is ASCII 1 year ago
John Zacarias Jekel d8afef06f4 Fix tests and benches 1 year ago
John Zacarias Jekel 145df94a80 Remove many of the translate_words functions, and make several others private. They are a bit of a maintenance pain and aren't a priority for performance improvements anyways 1 year ago
John Zacarias Jekel 02f2c30076 Tweak buffer sizes 1 year ago
John Zacarias Jekel 36779d0923 Improve performance even more! 1 year ago
John Zacarias Jekel c16ab972f6 Improve performancee by another 35% from the previous commit (83% overall) according to Callgrind 1 year ago
John Zacarias Jekel c85c98a5c7 Improve performance by 33% 1 year ago
John Zacarias Jekel c10248db01 Begin considering all upper case words 1 year ago
John Zacarias Jekel 3c43ea6cf2 Add the anslatetray-interactive program (to compete with latinify :) ) 1 year ago
John Zacarias Jekel 0150a771be Add Edge Cases to the docs 1 year ago
John Zacarias Jekel db99cfe29f Fix documentation and tests 1 year ago
John Zacarias Jekel 5b547aeac1 Increment minor version number 1 year ago
John Zacarias Jekel 088574115f Update performance info 1 year ago
John Zacarias Jekel 2979a07fea Fix issues with hyphens; now all tests pass! 1 year ago
John Zacarias Jekel dcb3c7fd88 When doing the performance section, I forgot to run the tests with a release build 1 year ago
John Zacarias Jekel a1a8d0cab8 Add another test for translate_with_style 1 year ago
John Zacarias Jekel 19a563217b Improve documentation; also discover that anslatortray struggles with hyphens... 1 year ago
John Zacarias Jekel df52ea5cb9 Begin adding tests/examples for translate_with_style() 1 year ago
John Zacarias Jekel 4e1f4989d9 Add tests for translate_word_with_style 1 year ago
John Zacarias Jekel c6a7994169 Add tests for translate_ferb 1 year ago
John Zacarias Jekel 1572513cee Add tests for translate_word_ferb 1 year ago
John Zacarias Jekel f2f40f8286 Improve documentation 1 year ago
John Zacarias Jekel 920c88fc0f Performance testing and experimental implementation of anslatetray-file 1 year ago
John Zacarias Jekel ffd9a3d589 Begin adding example executables that use the library 1 year ago
John Zacarias Jekel af27233629 Add support for Ferb Latin 1 year ago
John Zacarias Jekel 2bab7938bd Add benchmarks for various functions 1 year ago
John Zacarias Jekel a5aa74a3bb Split functions into seperate files 1 year ago
John Zacarias Jekel d45a3c4b4e Increment minor version number and reset patch number 1 year ago
John Zacarias Jekel 18a9899622 Add warning describing which functions are currently experimental 1 year ago
John Zacarias Jekel 5a5f0bd5fe Improve documentation 1 year ago
John Zacarias Jekel fd1683f013 Work on adding support for other suffixes 1 year ago
John Jekel 5390165e2f Begin planning out how different endings will be implemented 1 year ago
John Jekel 5f9877ede3 Increment the patch number, properly this time 1 year ago
  1. 37
      Cargo.toml
  2. 112
      README.md
  3. 1
      TODO integration tests for ALL regular and byte_string functions.txt
  4. 175
      src/anslatortray.rs
  5. 1060
      src/byte_string.rs
  6. 430
      src/lib.rs
  7. 397
      src/string.rs

@ -1,17 +1,46 @@
[package]
name = "anslatortray"
version = "0.1.1"
version = "0.5.0"
description = "A simple Rust library to translate from English to Pig Latin!"
authors = ["John Zacarias Jekel <john@jekel.ca>"]
readme = "README.md"
#homepage = ""
repository = "https://git.jekel.ca/JZJ/anslatortray-rs"
license = "MIT"
license-file = "LICENSE"
#license-file = "LICENSE"
edition = "2021"
keywords = ["pig", "latin", "text", "translate", "translator"]
categories = ["text-processing", "command-line-utilities", "localization"]
default-run = "anslatortray"
documentation = "https://docs.rs/anslatortray/latest/anslatortray/"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = []
nightly-features = ["nightly-features-benches"]
nightly-features-benches = []
[dependencies]
[lib]
name = "anslatortray"
path = "src/lib.rs"
[[bin]]
name = "anslatortray"
path = "src/anslatortray.rs"
[profile.dev]
incremental = true
[profile.release]
codegen-units = 1
strip = true
overflow-checks = false
panic = "abort"
lto = true
[profile.release-with-debug]
inherits = "release"
strip = false
overflow-checks = false
panic = "abort"
lto = false
debug = true

@ -1,4 +1,4 @@
# anslatortray-rs
# Anslatortray for Rust
A simple Rust library to translate from English to Pig Latin!
@ -6,40 +6,120 @@ A simple Rust library to translate from English to Pig Latin!
Essentially, the word is reorganized in an effort to hide its true meaning, which can be lots of fun!
The Anslatortray library can help out by converting any English text into Pig Latin quickly and easily.
# A Quick Example
You can translate multiple sentences, including numbers, punctuation, and spacing, with a single call to `translate()`.
The function handles edge cases quite well (words without vowels, one-letter words, contractions, etc.), though there is always room for improvement.
After adding Anslatortray as a dependency in your crate, try compiling this example code:
```rust
use anslatortray::translate;
fn main() {
//Prints "Ellohay orldway omfray ethay Anslatortray orfay Ustray!"
println!("{}", translate("Hello world from the Translator for Rust!"));
}
```
# Tell me more!
The Anslatortray library can help out by converting any English text into Pig Latin quickly and easily. It is **incredibly fast** (see the Performance section below) and **requires no dependencies**!
You can translate multiple sentences, including numbers, punctuation, and spacing, with a single call to `anslatortray::translate()`.
The function handles edge cases quite well (words without vowels, one-letter words, contractions, ALL CAPS, etc.), though there is always room for improvement.
If you have suggestions for how the project could be improved, please visit the repository's issues page on <a href="https://github.com/JZJisawesome/anslatortray-rs/issues">Github</a> or <a href="https://gitlab.com/JZJisawesome/anslatortray-rs/-/issues">GitLab</a> or contact me directly :)
# Examples
Be sure to check out the documentation at <https://docs.rs/anslatortray/latest/anslatortray/>!
# Building and Installation
If you wish to use the library in your crate, add anslatortray as a dependency and <a href="https://docs.rs/anslatortray/latest/anslatortray/">check out the documentation</a>.
If you wish to use the `anslatortray` standalone binary (shown in the next section), clone `https://git.jekel.ca/JZJ/anslatortray.git`, do `cargo build --release`, and you'll find the binary in the target/release directory.
Try compiling this example code:
See the <a href="https://git.jekel.ca/JZJ/anslatortray-rs/wiki/Building-And-Installing">wiki</a> for more information.
# anslatortray CLI Tool Usage
There are several options supported by the `anslatortray` command:
```
use anslatortray::translate;
> anslatortray --help
Anslatortray: frontend for the Anslatortray for Rust library
Options:
--help Print this helpful text!
--interactive Start an interactive translation session
--file Translate a file (requires two arguments, the file to translate and the destination)
--benchmark-file Benchmark translating a file (requires two arguments, the file to translate and the number of iterations to perform)
--translate-args Translates all remaining arguments provided and outputs them to stdout
--stdin-to-stdout Translates input from stdin directly to stdout
Avehay away oodgay ayday!
```
You can start an interactive session by specifying --interactive (or no arguments at all):
```
> anslatortray --interactive
Anslatortray: frontend for the Anslatortray for Rust library
Starting interactive mode!
Type what you'd like to translate and then press enter, or press Ctrl+C to exit...
anslatortray> The fitness gram pacer test is a multi-stage areobic endurance test that...
Ethay itnessfay amgray acerpay esttay isway away ultimay-agestay areobicway enduranceway esttay atthay...
//Prints "Ellohay orldway omfray ethay Anslatortray orfay Ustray!"
println!("{}", translate("Hello world from the Translator for Rust!"));
anslatortray> ^C
>
```
You can also pipe text into the command for use in scripting:
```
> echo "Testing pipes" | anslatortray --stdin-to-stdout > test_pipes.txt
Anslatortray: frontend for the Anslatortray for Rust library
> cat test_pipes.txt
Estingtay ipespay
```
If you'd like, you can even translate a text file:
```
> echo "Test file" > test_file.txt && cat test_file.txt
Test file
> anslatortray --file test_file.txt output_file.txt
Anslatortray: frontend for the Anslatortray for Rust library
Sucessful: took 3540ns to translate
> cat output_file.txt
Esttay ilefay
```
See <a href="https://git.jekel.ca/JZJ/anslatortray-rs/wiki/Using-the-anslatortray-binary">this wiki page</a> for more!
# Performance
Check out the <a href="https://git.jekel.ca/JZJ/anslatortray-rs/wiki/Performance">wiki page about Anslatortray's performance</a>!
Spoiler: `anslatortray::translate()` can process one word in under **50ns** on average!
# Useful Links
<a href="https://git.jekel.ca/JZJ/anslatortray-rs">Click here to visit the Anslatortray for Rust Git Repository!</a>.
You can also visit the <a href="https://github.com/JZJisawesome/anslatortray-rs/issues">Github</a> or <a href="https://gitlab.com/JZJisawesome/anslatortray-rs/-/issues">GitLab</a> mirrors to leave issues!
Anslatortray for Rust is a spiritual sucessor of my original <a href="https://git.jekel.ca/JZJ/anslatortray">Anslatortray</a> (for C++).
Be sure to check out the documentation at <https://docs.rs/anslatortray/latest/anslatortray/> and the wiki at <https://git.jekel.ca/JZJ/anslatortray-rs/wiki>.
# Anslatortray Code and Documentation Licence
Anslatortray for Rust is a spiritual sucessor of my original <a href="https://git.jekel.ca/JZJ/anslatortray">Anslatortray</a> (for C++).
MIT License
# Dependencies
Copyright (c) 2022 John Jekel
None other than the standard libraries!
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:
# Anslatortray Code and Documentation Licence
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Copyright (c) 2022 John Jekel
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.
MIT Licensed (see the LICENSE file for details)

@ -0,0 +1,175 @@
/* anslatortray
* Copyright (C) 2022 John Jekel
* See the LICENSE file at the root of the project for licensing info.
*
* Command-line frontend for the anslatortray library
*
*/
/* Imports */
use anslatortray::translate;
use anslatortray::byte_string;
/* Functions */
fn main() {
eprintln!("Anslatortray: frontend for the Anslatortray for Rust library\n");
//Get all arguments after the executable's name
let mut args: Vec<String> = std::env::args().collect();
args.remove(0);
if args.len() == 0 {
interactive(&args);
return;
}
let option = args[0].clone();
args.remove(0);
match option.as_str() {
"--help" => { help(); },
"--interactive" => { interactive(&args); },
"--file" => { file(&args); },
"--benchmark-file" => { benchmark_file(&args); },
"--translate-args" => { translate_args(&args); },
"--stdin-to-stdout" => { stdin_to_stdout(&args); },
bad_option => {
eprintln!("Error: {} is not a valid option", bad_option);
help();
}
}
}
fn help() {
eprintln!("Options:");
eprintln!("--help Print this helpful text!");
eprintln!("--interactive Start an interactive translation session");
eprintln!("--file Translate a file (requires two arguments, the file to translate and the destination)");
eprintln!("--benchmark-file Benchmark translating a file (requires two arguments, the file to translate and the number of iterations to perform)");
eprintln!("--translate-args Translates all remaining arguments provided and outputs them to stdout");
eprintln!("--stdin-to-stdout Translates input from stdin directly to stdout");
eprintln!("\n{}", translate("Have a good day!"));
}
fn interactive(args: &Vec<String>) {
if args.len() != 0 {
eprintln!("Error: didn't expect any arguments");
help();
return;
}
eprintln!("Starting interactive mode!");
eprintln!("Type what you'd like to translate and then press enter, or press Ctrl+C to exit...\n");
let stdin = std::io::stdin();
let mut line_buffer = String::new();
loop {
eprint!("anslatortray> ");
stdin.read_line(&mut line_buffer).unwrap();
eprintln!("{}", translate(&line_buffer));
line_buffer.truncate(0);
}
}
fn file(args: &Vec<String>) {
eprintln!("Note: anslatortray --file is highly experimental and has poor error handling. You have been warned.");
if args.len() != 2 {
eprintln!("Error: expected two arguments, two arguments, the file to translate and the destination");
help();
return;
}
//TODO error handling
//TODO switch to using byte_string for efficiency
let input_file = &args[0];
let output_file = &args[1];
let file_contents = std::fs::read_to_string(input_file).unwrap();
let start_time = std::time::Instant::now();
let translated_file_contents = translate(&file_contents);
let time_to_translate = start_time.elapsed();
std::fs::write(output_file, &translated_file_contents).unwrap();
eprintln!("Sucessful: took {}ns to translate", time_to_translate.as_nanos());
}
fn benchmark_file(args: &Vec<String>) {
eprintln!("Note: anslatortray --benchmark-file is highly experimental and has poor error handling. You have been warned.");
if args.len() != 2 {
eprintln!("Error: expected two arguments, the file to translate and the number of iterations to perform");
help();
return;
}
//TODO error handling
let input_file = &args[0];
let iterations = args[1].parse::<u128>().unwrap();//TODO error handling
let file_contents = std::fs::read_to_string(input_file).unwrap();
let mut total_duration_regular = std::time::Duration::new(0, 0);
for _ in 0..iterations {
let start_time = std::time::Instant::now();
let translated_file_contents = translate(&file_contents);
let time_to_translate = start_time.elapsed();
total_duration_regular += time_to_translate;
std::fs::write("/dev/null", &translated_file_contents).unwrap();//TODO avoid needing unix
}
eprintln!("Sucessful: Regular translation took {}ns to translate on average over {} runs.", total_duration_regular.as_nanos() / iterations, iterations);
let mut total_duration_byte_string = std::time::Duration::new(0, 0);
let mut translated_file_contents = Vec::<u8>::new();//TODO set a sane initial size
for _ in 0..iterations {
let start_time = std::time::Instant::now();
translated_file_contents.truncate(0);
byte_string::translate(file_contents.as_bytes(), &mut translated_file_contents);
let time_to_translate = start_time.elapsed();
total_duration_byte_string += time_to_translate;
std::fs::write("/dev/null", &translated_file_contents).unwrap();//TODO avoid needing unix
}
eprintln!("Sucessful: Byte-string translation with reused allocations took {}ns to translate on average over {} runs.", total_duration_byte_string.as_nanos() / iterations, iterations);
}
fn translate_args(args: &Vec<String>) {
if args.len() == 0 {
eprintln!("Error: expected at least one string to translate");
help();
return;
}
//Translate the arguments and print them out for the user
for string in args {
print!("{} ", translate(&string));
}
println!();
}
fn stdin_to_stdout(args: &Vec<String>) {
use std::io::{Read, Write};
if args.len() != 0 {
eprintln!("Error: didn't expect any arguments");
help();
return;
}
let mut stdin = std::io::stdin();
let mut stdout = std::io::stdout();
let mut buffer = String::new();
while let Ok(bytes_read) = stdin.read_to_string(&mut buffer) {
if bytes_read == 0 { return; }
write!(stdout, "{}", translate(&buffer)).unwrap();//TODO do this more efficiently (avoid format string)
buffer.truncate(0);//TODO is this needed here?
}
}

File diff suppressed because it is too large Load Diff

@ -1,22 +1,14 @@
//!Anslatortray for Rust
//!Anslatortray for Rust: A simple Rust library to translate from English to Pig Latin.
//!
//!Welcome to the Anslatortray Documentation!
//!
//!A simple Rust library to translate from English to Pig Latin.
//!# Building and Installation
//!
//!If you wish to use the library in your crate, add anslatortray as a dependency and follow along with the examples below, or check out the rest of the documentation.
//!
//!<a href="https://en.wikipedia.org/wiki/Pig_Latin">Wikipedia's definition of Pig Latin</a> is "a language game or argot in which words in English are altered, usually by adding a fabricated suffix or by moving the onset or initial consonant or consonant cluster of a word to the end of the word and adding a vocalic syllable to create such a suffix."
//!See the <a href="https://git.jekel.ca/JZJ/anslatortray-rs/wiki/Building-And-Installing">wiki</a> for more information.
//!
//!Essentially, the word is reorganized in an effort to hide its true meaning, which can be lots of fun!
//!
//!The Anslatortray library can help out by converting any English text into Pig Latin quickly and easily.
//!
//!You can translate multiple sentences, including numbers, punctuation, and spacing, with a single call to [`translate()`].
//!The function handles edge cases quite well (words without vowels, one-letter words, contractions, etc.), though there is always room for improvement.
//!
//!If you have suggestions for how the project could be improved, please visit the repository's issues page on <a href="https://github.com/JZJisawesome/anslatortray-rs/issues">Github</a> or <a href="https://gitlab.com/JZJisawesome/anslatortray-rs/-/issues">GitLab</a> or contact me directly :)
//!
//!# Examples
//!# Library Examples
//!
//!Try compiling this example code:
//!
@ -27,395 +19,55 @@
//!println!("{}", translate("Hello world from the Translator for Rust!"));
//!```
//!
//!Anslatortray also supports using the "yay" suffix instead in special cases if you prefer that:
//!
//!```
//!use anslatortray::translate_yay;
//!
//!//Prints "Utbay Iyay eferpray ethay ayyay-ylestay igpay atinlay!"
//!println!("{}", translate_yay("But I prefer the yay-style pig latin!"));
//!```
//!
//!It also supports Ferb Latin from Phineas and Ferb:
//!
//!```
//!use anslatortray::translate_ferb;
//!
//!//Prints "Erewherb's Erryperb?"
//!println!("{}", translate_ferb("Where's Perry?"));
//!```
//!
//!If none of these suit your needs, you can also choose your own suffixes with [`translate_with_style()`]
//!
//!If you want even more speed than the regular translation functions bring to the table, check out the [`byte_string`] module.
//!
//!# Useful Links
//!<a href="https://git.jekel.ca/JZJ/anslatortray-rs">Click here to visit the Anslatortray for Rust Git Repository!</a>.
//!
//!You can also visit the <a href="https://github.com/JZJisawesome/anslatortray-rs/issues">Github</a> or <a href="https://gitlab.com/JZJisawesome/anslatortray-rs/-/issues">GitLab</a> mirrors to leave issues!
//!
//!Be sure to check out the <a href="https://crates.io/crates/anslatortray">crates.io page</a> and the wiki at <https://git.jekel.ca/JZJ/anslatortray-rs/wiki>.
//!
//!Anslatortray for Rust is a spiritual sucessor of my original <a href="https://git.jekel.ca/JZJ/anslatortray">Anslatortray</a> (for C++).
//!
//!# Anslatortray Code and Documentation Licence
//!MIT License
//!# Dependencies
//!
//!Copyright (c) 2022 John Jekel
//!None other than the standard libraries!
//!
//!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:
//!# Anslatortray Code and Documentation Licence
//!
//!The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//!Copyright (c) 2022 John Jekel
//!
//!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.
///Translates a multi-word string (including punctuation) into Pig Latin!
///
///# Examples
///
///```
///use anslatortray::{translate, VOWEL_START_STYLE};
///
///assert_eq!(translate("Hello world from the coolest Pig Latin translator!"), "Ellohay orldway omfray ethay oolestcay Igpay Atinlay anslatortray!");
///
///assert_eq!(translate("This library can translate any English text. It can even handle multiple sentences!"),
/// if VOWEL_START_STYLE == "way" { "Isthay ibrarylay ancay anslatetray anyway Englishway exttay. Itway ancay evenway andlehay ultiplemay entencessay!" }
/// else if VOWEL_START_STYLE == "yay" { "Isthay ibrarylay ancay anslatetray anyyay Englishyay exttay. Ityay ancay evenyay andlehay ultiplemay entencessay!" }
/// else { panic!(); }
///);
///
///assert_eq!(translate("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!"),
/// if VOWEL_START_STYLE == "way" { "Etlay's ytray omesay edgeway asescay. Atthay isway away ontractioncay, asway ellway asway away ordway erewhay ethay onlyway owelvay isway yway. Eatnay, allway atthay orksway!" }
/// else if VOWEL_START_STYLE == "yay" { "Etlay's ytray omesay edgeyay asescay. Atthay isyay ayay ontractioncay, asyay ellway asyay ayay ordway erewhay ethay onlyyay owelvay isyay yyay. Eatnay, allyay atthay orksway!" }
/// else { panic!(); }
///);
///assert_eq!(translate("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ"),
/// if VOWEL_START_STYLE == "way" { "Atwhay ifway away ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZay" }
/// else if VOWEL_START_STYLE == "yay" { "Atwhay ifyay ayay ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZay" }
/// else { panic!(); }
/// );
/// assert_eq!(translate("Cool, so the heuristics make pretty good guesses with what they're fed!"),
/// "Oolcay, osay ethay euristicshay akemay ettypray oodgay uessesgay ithway atwhay eythay're edfay!"
/// );
///```
pub fn translate(english: &str) -> String {
if english.is_empty() {
return "".to_string();
}
let mut pig_latin_string: String = "".to_string();
let mut first_iteration: bool = true;
for word in english.split(&[' ', '\t', '\n']) {
if !first_iteration { pig_latin_string.push(' '); }//Seperate words by spaces regardless of how they were seperated before
pig_latin_string.push_str(translate_word(word).as_str());
first_iteration = false;
}
return pig_latin_string;
}
///The suffix appended to a word the starts with a vowel instead of the usual "ay"
///
///Commonly this is either "way" or "yay". I prefer the former, but you can choose
///between the two by specifying the feature "way" or "yay" respectively in Cargo.
///
///You can also choose from more exotic endings, like "werb" or "yerb" for Ferb latin, though
///you'll have to modify this file (src/lib.rs) to change this manually. This includes changes
///to the normal suffix in [`translate_word()`] and updates to the tests.
///
///If you'd like to see another ending available as a Cargo feature, contact me and I'll implement it
pub const VOWEL_START_STYLE: &str = "yay";//TODO make this configurable via a Cargo feature
///Translates a single word or contraction string into Pig Latin!
///
///Can have leading and trailing punctuation or whitespace.
///It generally does a pretty good job with valid english words and contractions,
///and leaves symbols and spaces mostly unchanged.
///
///This is a helper function used by [`translate()`], but
///it is publically exposed as potential users may find this useful.
///
///# Examples
///
///```
///use anslatortray::{translate_word, VOWEL_START_STYLE};
///
///assert_eq!(translate_word("Hello"), "Ellohay");
///assert_eq!(translate_word("World!"), "Orldway!");
///
///assert_eq!(translate_word("This"), "Isthay");
///assert_eq!(translate_word("is"), "is".to_string() + &VOWEL_START_STYLE.to_string());
///assert_eq!(translate_word("a"), "a".to_string() + &VOWEL_START_STYLE.to_string());
///assert_eq!(translate_word("test"), "esttay".to_string());
///assert_eq!(translate_word("of"), "of".to_string() + &VOWEL_START_STYLE.to_string());
///assert_eq!(translate_word("the"), "ethay");
///assert_eq!(translate_word("function"), "unctionfay");
///assert_eq!(translate_word("translate_"), "anslatetray_");
///assert_eq!(translate_word("word."), "ordway.");
///
///assert_eq!(translate_word("I"), "I".to_string() + &VOWEL_START_STYLE.to_string());
///assert_eq!(translate_word("Love"), "Ovelay");
///assert_eq!(translate_word("Pig"), "Igpay");
///assert_eq!(translate_word("Latin!"), "Atinlay!");
///
///assert_eq!(translate_word("You"), "Ouyay");//Y isn't a vowel here
///assert_eq!(translate_word("should"), "ouldshay");
///assert_eq!(translate_word("try"), "ytray");//Y is a vowel here
///assert_eq!(translate_word("yougurt,"), "ougurtyay,");//Y isn't a vowel here
///assert_eq!(translate_word("it's"), "it".to_string() + &VOWEL_START_STYLE.to_string() + "'s");//Contraction
///assert_eq!(translate_word("quite"), "uiteqay");//Awful to pronounce, but correct
///assert_eq!(translate_word("nice!"), "icenay!");
///
///assert_eq!(translate_word(" !@#$%^&*()_+{}|\":>?~`\\][';/.,\t\n"), " !@#$%^&*()_+{}|\":>?~`\\][';/.,\t\n");//Lots of symbols
///assert_eq!(translate_word(" !@#$%^&*()_+{}word|\":>?~`\\][';/.,\t\n"), " !@#$%^&*()_+{}ordway|\":>?~`\\][';/.,\t\n");//Symbols around a word
///assert_eq!(translate_word("12345678"), "12345678");//A number
///assert_eq!(translate_word("100 pizzas"), "100 izzaspay");//A number before a word
///assert_eq!(translate_word("over 9000"), "over".to_string() + &VOWEL_START_STYLE.to_string() + " 9000");//A number after a word
///```
pub fn translate_word(english_word: &str) -> String {
if english_word.is_empty() {
return "".to_string();
}
let mut pig_latin_word: String = "".to_string();
let mut iterator = english_word.chars().peekable();
//Copy leading symbols/whitespace until the first letter
let first_letter: char;
loop {
match iterator.next() {
None => { return english_word.to_string(); },//There are only symbols/whitespace in the word
Some(character) => {
if character.is_alphabetic() {
first_letter = character;//We found the first character of the word/contraction
break;
} else {
pig_latin_word.push(character);//Copy whitespace/symbol
}
}
}
}
//TODO what if the word is all uppercase?
//As a herustic, we consider Y to be a vowel when it is not at the start of the word
//However, if any word is only one letter long, this takes priority and the word is treated like a vowel
let first_letter_was_vowel: bool = {
is_vowel(first_letter).unwrap()//Not including y
|| if let Some(character) = iterator.peek() { !character.is_alphabetic() } else { false }//Non-alphabetic character or word ends after the first letter
};
let mut starting_consonants: String = "".to_string();
if first_letter_was_vowel {
pig_latin_word.push(first_letter);
} else {
let first_char_was_upper = first_letter.is_ascii_uppercase();
starting_consonants.push(first_letter.to_ascii_lowercase());
//Grab all of the starting consonants, and push the first vowel we enounter to pig_latin_word
loop {
match iterator.next() {
None => { break; },//The word has no vowels, but it is a herustic to pass it on so that ex. the acroynm binary code decimal or bcd becomes bcdway, etc.
Some(character) => {
if character.is_alphabetic() {
if is_vowel(character).unwrap() || is_y(character).unwrap() {//As a herustic, we consider Y to be a vowel when it is not at the start of the word
//The vowel is the first letter of the word; we want it match the capitalization of the first letter of the original word
if first_char_was_upper {
pig_latin_word.push(character.to_ascii_uppercase());
} else {
pig_latin_word.push(character.to_ascii_lowercase());
}
break;
} else {
starting_consonants.push(character);
}
} else {//The word ended without vowels or we met an apostrophe
break;//It is a herustic to pass it on so that ex. the letter y becomes yway, the word a becomes away, etc.
}
}
}
}
}
//Copy all of the remaining letters up to the end of the word or up until we enounter the ' as part of a contraction
let trailing_character: Option<char>;
loop {
match iterator.next() {
None => {
trailing_character = None;
break;
},//End of the word
Some(character) => {
if character.is_alphabetic() {
pig_latin_word.push(character);
} else {
trailing_character = Some(character);
break;
}
}
}
}
//Copy starting consonants and add ay, or add the VOWEL_START_STYLE depending on the circumstances
if first_letter_was_vowel {
pig_latin_word.push_str(VOWEL_START_STYLE);
} else {
pig_latin_word.push_str(&starting_consonants);
pig_latin_word.push_str("ay");
}
//Re-add the trailing character we "accidentally" took in the previous loop (if we do in fact have one)
if let Some(character) = trailing_character {
pig_latin_word.push(character);
}
//Copy any remaining characters as-is
loop {
match iterator.next() {
None => { break; },//End of the word
Some(character) => { pig_latin_word.push(character); },
}
}
return pig_latin_word;
}
///Returns whether a letter is a vowel or not.
///
///If the parameter is a letter, returns Some(true) if it is a vowel, and Some(false) otherwise.
///If the parameter isn't a letter, it will return None
///
///This is a helper function used by [`translate_word()`], but
///it is publically exposed as potential users may find this useful.
///
///# Examples
///
///```
///for letter in "aeiouAEIOU".chars() {
/// assert!(anslatortray::is_vowel(letter).unwrap());
///}
///
///for letter in "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ".chars() {
/// assert!(!anslatortray::is_vowel(letter).unwrap());
///}
///
///for not_letter in " !@#$%^&*()_+{}|\":>?~`\\][';/.,".chars() {
/// assert!(matches!(anslatortray::is_vowel(not_letter), None));
///}
///```
pub fn is_vowel(letter: char) -> Option<bool> {
if !letter.is_alphabetic() {
return None;
}
match letter.to_ascii_lowercase() {
'a' | 'e' | 'i' | 'o' | 'u' => { return Some(true); }
_ => { return Some(false); }
}
}
///Returns whether a letter is y or not.
///
///If the parameter is a letter, returns Some(true) if it is y, and Some(false) otherwise.
///If the parameter isn't a letter, it will return None
///
///This is a helper function used by [`translate_word()`], but
///it is publically exposed as potential users may find this useful.
///
///# Examples
///
///```
///for letter in "yY".chars() {
/// assert!(anslatortray::is_y(letter).unwrap());
///}
///
///for letter in "abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXZ".chars() {
/// assert!(!anslatortray::is_y(letter).unwrap());
///}
///
///for not_letter in " !@#$%^&*()_+{}|\":>?~`\\][';/.,\t\n".chars() {
/// assert!(matches!(anslatortray::is_y(not_letter), None));
///}
///```
pub fn is_y(letter: char) -> Option<bool> {
if !letter.is_alphabetic() {
return None;
}
return Some(letter.to_ascii_lowercase() == 'y');
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_translate() {
assert_eq!(translate("Hello world from the coolest Pig Latin translator!"), "Ellohay orldway omfray ethay oolestcay Igpay Atinlay anslatortray!");
assert_eq!(translate("This library can translate any English text. It can even handle multiple sentences!"),
if VOWEL_START_STYLE == "way" { "Isthay ibrarylay ancay anslatetray anyway Englishway exttay. Itway ancay evenway andlehay ultiplemay entencessay!" }
else if VOWEL_START_STYLE == "yay" { "Isthay ibrarylay ancay anslatetray anyyay Englishyay exttay. Ityay ancay evenyay andlehay ultiplemay entencessay!" }
else { panic!(); }
);
}
#[test]
fn test_translate_edgecases() {
assert_eq!(translate("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!"),
if VOWEL_START_STYLE == "way" { "Etlay's ytray omesay edgeway asescay. Atthay isway away ontractioncay, asway ellway asway away ordway erewhay ethay onlyway owelvay isway yway. Eatnay, allway atthay orksway!" }
else if VOWEL_START_STYLE == "yay" { "Etlay's ytray omesay edgeyay asescay. Atthay isyay ayay ontractioncay, asyay ellway asyay ayay ordway erewhay ethay onlyyay owelvay isyay yyay. Eatnay, allyay atthay orksway!" }
else { panic!(); }
);
assert_eq!(translate("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ"),
if VOWEL_START_STYLE == "way" { "Atwhay ifway away ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZay" }
else if VOWEL_START_STYLE == "yay" { "Atwhay ifyay ayay ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZay" }
else { panic!(); }
);
assert_eq!(translate("Cool, so the heuristics make pretty good guesses with what they're fed!"),
"Oolcay, osay ethay euristicshay akemay ettypray oodgay uessesgay ithway atwhay eythay're edfay!"
);
}
#[test]
fn test_translate_word() {
assert_eq!(translate_word("Hello"), "Ellohay");
assert_eq!(translate_word("World!"), "Orldway!");
assert_eq!(translate_word("This"), "Isthay");
assert_eq!(translate_word("is"), "is".to_string() + &VOWEL_START_STYLE.to_string());
assert_eq!(translate_word("a"), "a".to_string() + &VOWEL_START_STYLE.to_string());
assert_eq!(translate_word("test"), "esttay".to_string());
assert_eq!(translate_word("of"), "of".to_string() + &VOWEL_START_STYLE.to_string());
assert_eq!(translate_word("the"), "ethay");
assert_eq!(translate_word("function"), "unctionfay");
assert_eq!(translate_word("translate_"), "anslatetray_");
assert_eq!(translate_word("word."), "ordway.");
assert_eq!(translate_word("I"), "I".to_string() + &VOWEL_START_STYLE.to_string());
assert_eq!(translate_word("Love"), "Ovelay");
assert_eq!(translate_word("Pig"), "Igpay");
assert_eq!(translate_word("Latin!"), "Atinlay!");
assert_eq!(translate_word("You"), "Ouyay");//Y isn't a vowel here
assert_eq!(translate_word("should"), "ouldshay");
assert_eq!(translate_word("try"), "ytray");//Y is a vowel here
assert_eq!(translate_word("yougurt,"), "ougurtyay,");//Y isn't a vowel here
assert_eq!(translate_word("it's"), "it".to_string() + &VOWEL_START_STYLE.to_string() + "'s");//Contraction
assert_eq!(translate_word("quite"), "uiteqay");//Awful to pronounce, but correct
assert_eq!(translate_word("nice!"), "icenay!");
assert_eq!(translate_word(" !@#$%^&*()_+{}|\":>?~`\\][';/.,\t\n"), " !@#$%^&*()_+{}|\":>?~`\\][';/.,\t\n");//Lots of symbols
assert_eq!(translate_word(" !@#$%^&*()_+{}word|\":>?~`\\][';/.,\t\n"), " !@#$%^&*()_+{}ordway|\":>?~`\\][';/.,\t\n");//Symbols around a word
assert_eq!(translate_word("12345678"), "12345678");//A number
assert_eq!(translate_word("100 pizzas"), "100 izzaspay");//A number before a word
assert_eq!(translate_word("over 9000"), "over".to_string() + &VOWEL_START_STYLE.to_string() + " 9000");//A number after a word
}
#[test]
fn test_is_vowel() {
for letter in "aeiouAEIOU".chars() {
assert!(is_vowel(letter).unwrap());
}
//!MIT Licensed (see the LICENSE file for details)
for letter in "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ".chars() {
assert!(!is_vowel(letter).unwrap());
}
/* Nightly Features */
for not_letter in " !@#$%^&*()_+{}|\":>?~`\\][';/.,\t\n".chars() {
assert!(matches!(is_vowel(not_letter), None));
}
}
//Only enabled if the relevant Cargo feature is
#![cfg_attr(feature = "nightly-features-benches", feature(test))]
#[test]
fn test_is_y() {
for letter in "yY".chars() {
assert!(is_y(letter).unwrap());
}
/* Imports */
for letter in "abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXZ".chars() {
assert!(!is_y(letter).unwrap());
}
pub mod byte_string;
mod string;
for not_letter in " !@#$%^&*()_+{}|\":>?~`\\][';/.,\t\n".chars() {
assert!(matches!(is_y(not_letter), None));
}
}
}
pub use string::{translate, translate_way, translate_yay, translate_hay, translate_ferb, translate_with_style};

@ -0,0 +1,397 @@
/* string.rs
* By: John Jekel
* Copyright (C) 2022 John Jekel
* See the LICENSE file at the root of the project for licensing info.
*
* Translation functions operating on &str and String (the ones most users will want to use)
*
*/
/* Imports */
use crate::byte_string::translate_with_style_lower_and_upper_suffixes as translate_byte_string_with_style_lower_and_upper_suffixes;
/* Functions */
///Translates a multi-word string (including punctuation) into Pig Latin!
///
///Uses the default suffix and special_case_suffix, "ay" and "way" respectively when calling [`translate_with_style()`].
///
///Equivalent to [`translate_way()`].
///
///# Examples
///
///```
///use anslatortray::translate;
///
///assert_eq!(translate("Hello world from the coolest Pig Latin translator!"), "Ellohay orldway omfray ethay oolestcay Igpay Atinlay anslatortray!");
///
///assert_eq!(translate("This library can translate any English text. It can even handle multiple sentences!"),
/// "Isthay ibrarylay ancay anslatetray anyway Englishway exttay. Itway ancay evenway andlehay ultiplemay entencessay!"
///);
///
///assert_eq!(translate("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!"),
/// "Etlay's ytray omesay edgeway asescay. Atthay isway away ontractioncay, asway ellway asway away ordway erewhay ethay onlyway owelvay isway yway. Eatnay, allway atthay orksway!"
///);
///
///assert_eq!(translate("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxz"),
/// "Atwhay ifway away ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzay"
///);
///
///assert_eq!(translate("Cool, so the heuristics make pretty good guesses with what they're fed!"),
/// "Oolcay, osay ethay euristicshay akemay ettypray oodgay uessesgay ithway atwhay eythay're edfay!"
///);
///
///assert_eq!(translate("Hello-world"), "Ellohay-orldway");
///assert_eq!(translate("Hyphens-are-difficult-aren't-they?"), "Yphenshay-areway-ifficultday-arenway't-eythay?");
///```
pub fn translate(english: &str) -> String {
return translate_way(english);
}
///Translates a multi-word string (including punctuation) into Pig Latin (way-style)!
///
///Uses the suffix and special_case_suffix "ay" and "way" respectively when calling [`translate_with_style()`].
///
///# Examples
///
///```
///use anslatortray::translate_way;
///
///assert_eq!(translate_way("Hello world from the coolest Pig Latin translator!"), "Ellohay orldway omfray ethay oolestcay Igpay Atinlay anslatortray!");
///
///assert_eq!(translate_way("This library can translate any English text. It can even handle multiple sentences!"),
/// "Isthay ibrarylay ancay anslatetray anyway Englishway exttay. Itway ancay evenway andlehay ultiplemay entencessay!"
///);
///
///assert_eq!(translate_way("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!"),
/// "Etlay's ytray omesay edgeway asescay. Atthay isway away ontractioncay, asway ellway asway away ordway erewhay ethay onlyway owelvay isway yway. Eatnay, allway atthay orksway!"
///);
///
///assert_eq!(translate_way("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxz"),
/// "Atwhay ifway away ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzay"
///);
///
///assert_eq!(translate_way("Cool, so the heuristics make pretty good guesses with what they're fed!"),
/// "Oolcay, osay ethay euristicshay akemay ettypray oodgay uessesgay ithway atwhay eythay're edfay!"
///);
///
///assert_eq!(translate_way("Hello-world"), "Ellohay-orldway");
///assert_eq!(translate_way("Hyphens-are-difficult-aren't-they?"), "Yphenshay-areway-ifficultday-arenway't-eythay?");
///```
pub fn translate_way(english: &str) -> String {
return translate_with_style_lower_and_upper_suffixes(english, "ay", "way", "AY", "WAY");
}
///Translates a multi-word string (including punctuation) into Pig Latin (yay-style)!
///
///Uses the suffix and special_case_suffix "ay" and "yay" respectively when calling [`translate_with_style()`].
///
///# Examples
///
///```
///use anslatortray::translate_yay;
///
///assert_eq!(translate_yay("Hello world from the coolest Pig Latin translator!"), "Ellohay orldway omfray ethay oolestcay Igpay Atinlay anslatortray!");
///
///assert_eq!(translate_yay("This library can translate any English text. It can even handle multiple sentences!"),
/// "Isthay ibrarylay ancay anslatetray anyyay Englishyay exttay. Ityay ancay evenyay andlehay ultiplemay entencessay!"
///);
///
///assert_eq!(translate_yay("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!"),
/// "Etlay's ytray omesay edgeyay asescay. Atthay isyay ayay ontractioncay, asyay ellway asyay ayay ordway erewhay ethay onlyyay owelvay isyay yyay. Eatnay, allyay atthay orksway!"
///);
///
///assert_eq!(translate_yay("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxz"),
/// "Atwhay ifyay ayay ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzay"
///);
///
///assert_eq!(translate_yay("Cool, so the heuristics make pretty good guesses with what they're fed!"),
/// "Oolcay, osay ethay euristicshay akemay ettypray oodgay uessesgay ithway atwhay eythay're edfay!"
///);
///
///assert_eq!(translate_yay("Hello-world"), "Ellohay-orldway");
///assert_eq!(translate_yay("Hyphens-are-difficult-aren't-they?"), "Yphenshay-areyay-ifficultday-arenyay't-eythay?");
///```
pub fn translate_yay(english: &str) -> String {
return translate_with_style_lower_and_upper_suffixes(english, "ay", "yay", "AY", "YAY");
}
///Translates a multi-word string (including punctuation) into Pig Latin (hay-style)!
///
///Uses the suffix and special_case_suffix "ay" and "hay" respectively when calling [`translate_with_style()`].
///
///# Examples
///
///```
///use anslatortray::translate_hay;
///
///assert_eq!(translate_hay("Hello world from the coolest Pig Latin translator!"), "Ellohay orldway omfray ethay oolestcay Igpay Atinlay anslatortray!");
///
///assert_eq!(translate_hay("This library can translate any English text. It can even handle multiple sentences!"),
/// "Isthay ibrarylay ancay anslatetray anyhay Englishhay exttay. Ithay ancay evenhay andlehay ultiplemay entencessay!"
///);
///
///assert_eq!(translate_hay("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!"),
/// "Etlay's ytray omesay edgehay asescay. Atthay ishay ahay ontractioncay, ashay ellway ashay ahay ordway erewhay ethay onlyhay owelvay ishay yhay. Eatnay, allhay atthay orksway!"
///);
///
///assert_eq!(translate_hay("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxz"),
/// "Atwhay ifhay ahay ordway ashay onay owelsvay, ikelay isthay: bcdfghjklmnpqrstvwxzay"
///);
///
///assert_eq!(translate_hay("Cool, so the heuristics make pretty good guesses with what they're fed!"),
/// "Oolcay, osay ethay euristicshay akemay ettypray oodgay uessesgay ithway atwhay eythay're edfay!"
///);
///
///assert_eq!(translate_hay("Hello-world"), "Ellohay-orldway");
///assert_eq!(translate_hay("Hyphens-are-difficult-aren't-they?"), "Yphenshay-arehay-ifficultday-arenhay't-eythay?");
///```
pub fn translate_hay(english: &str) -> String {
return translate_with_style_lower_and_upper_suffixes(english, "ay", "hay", "AY", "HAY");
}
///Translates a multi-word string (including punctuation) into Ferb Latin!
///
///Uses the suffix and special_case_suffix "erb" and "ferb" respectively when calling [`translate_with_style()`].
///
///# Examples
///
///```
///use anslatortray::translate_ferb;
///
///assert_eq!(translate_ferb("Hello world from the coolest Ferb Latin translator!"), "Elloherb orldwerb omfrerb etherb oolestcerb Erbferb Atinlerb anslatortrerb!");
///
///assert_eq!(translate_ferb("This library can translate any English text. It can even handle multiple sentences!"),
/// "Istherb ibrarylerb ancerb anslatetrerb anyferb Englishferb extterb. Itferb ancerb evenferb andleherb ultiplemerb entencesserb!"
///);
///
///assert_eq!(translate_ferb("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!"),
/// "Etlerb's ytrerb omeserb edgeferb asescerb. Attherb isferb aferb ontractioncerb, asferb ellwerb asferb aferb ordwerb erewherb etherb onlyferb owelverb isferb yferb. Eatnerb, allferb attherb orkswerb!"
///);
///assert_eq!(translate_ferb("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxz"),
/// "Atwherb ifferb aferb ordwerb asherb onerb owelsverb, ikelerb istherb: bcdfghjklmnpqrstvwxzerb"
///);
///assert_eq!(translate_ferb("Cool, so the heuristics make pretty good guesses with what they're fed!"),
/// "Oolcerb, oserb etherb euristicsherb akemerb ettyprerb oodgerb uessesgerb ithwerb atwherb eytherb're edferb!"
///);
///
///assert_eq!(translate_ferb("Hello-world"), "Elloherb-orldwerb");
///assert_eq!(translate_ferb("Hyphens-are-difficult-aren't-they?"), "Yphensherb-areferb-ifficultderb-arenferb't-eytherb?");
///```
pub fn translate_ferb(english: &str) -> String {
return translate_with_style_lower_and_upper_suffixes(english, "erb", "ferb", "ERB", "FERB");
}
///Translates a multi-word string (including punctuation) into a custom-styled play language!
///
///Pass the string you wish to translate, the suffix you wish to have appended to most words, and the suffix
///you wish to have appended in various special-cases (such as when a word is only one letter or starts with a vowel).
///
///Note: The suffixes must be entirely lower-case or weird results may occur.
///
///# Examples
///
///```
///use anslatortray::translate_with_style;
///
///let suffix = "ancy";
///let special_case_suffix = "fancy";
///
///assert_eq!(translate_with_style("Hello world from the coolest Pig Latin translator!", suffix, special_case_suffix),
/// "Ellohancy orldwancy omfrancy ethancy oolestcancy Igpancy Atinlancy anslatortrancy!"
///);
///
///assert_eq!(translate_with_style("This library can translate any English text. It can even handle multiple sentences!", suffix, special_case_suffix),
/// "Isthancy ibrarylancy ancancy anslatetrancy anyfancy Englishfancy exttancy. Itfancy ancancy evenfancy andlehancy ultiplemancy entencessancy!"
///);
///
///assert_eq!(translate_with_style("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!", suffix, special_case_suffix),
/// "Etlancy's ytrancy omesancy edgefancy asescancy. Atthancy isfancy afancy ontractioncancy, asfancy ellwancy asfancy afancy ordwancy erewhancy ethancy onlyfancy owelvancy isfancy yfancy. Eatnancy, allfancy atthancy orkswancy!"
///);
///
///assert_eq!(translate_with_style("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxz", suffix, special_case_suffix),
/// "Atwhancy iffancy afancy ordwancy ashancy onancy owelsvancy, ikelancy isthancy: bcdfghjklmnpqrstvwxzancy"
///);
///
///assert_eq!(translate_with_style("Cool, so the heuristics make pretty good guesses with what they're fed!", suffix, special_case_suffix),
/// "Oolcancy, osancy ethancy euristicshancy akemancy ettyprancy oodgancy uessesgancy ithwancy atwhancy eythancy're edfancy!"
///);
///
///assert_eq!(translate_with_style("Hello-world", suffix, special_case_suffix), "Ellohancy-orldwancy");
///
///assert_eq!(translate_with_style("Hyphens-are-difficult-aren't-they?", suffix, special_case_suffix), "Yphenshancy-arefancy-ifficultdancy-arenfancy't-eythancy?");
///```
pub fn translate_with_style(english: &str, suffix_lower: &str, special_case_suffix_lower: &str) -> String {
//Convert the suffix and special_case_suffix we were provided to uppercase for words that are capitalized
let mut suffix_upper = String::with_capacity(suffix_lower.len());
for letter in suffix_lower.chars() {
suffix_upper.push(letter.to_ascii_uppercase());
}
let mut special_case_suffix_upper = String::with_capacity(special_case_suffix_lower.len());
for letter in special_case_suffix_lower.chars() {
special_case_suffix_upper.push(letter.to_ascii_uppercase());
}
return translate_with_style_lower_and_upper_suffixes (
english,
suffix_lower, special_case_suffix_lower, &suffix_upper, &special_case_suffix_upper
);
}
//More efficient: Does not need to convert to upppercase at runtime
fn translate_with_style_lower_and_upper_suffixes (
english: &str,
suffix_lower: &str, special_case_suffix_lower: &str, suffix_upper: &str, special_case_suffix_upper: &str
) -> String {
//Convert the string slices to byte slices and translate those (only ASCII letters are affected, non-letters or UTF-8 are preserved)
let mut pig_latin_string_bytes = Vec::<u8>::with_capacity(english.len() * 2);//Plenty of headroom in case the words are very small or the suffixes are long
translate_byte_string_with_style_lower_and_upper_suffixes (
english.as_bytes(),
suffix_lower.as_bytes(), special_case_suffix_lower.as_bytes(), suffix_upper.as_bytes(), special_case_suffix_upper.as_bytes(),
&mut pig_latin_string_bytes
);
//This is safe since translate_byte_string_with_style does not touch any unicode bytes (it just copies them)
return unsafe { String::from_utf8_unchecked(pig_latin_string_bytes) };
}
/* Tests */
#[cfg(test)]
mod tests {
use super::*;
const SUFFIX_SPECIAL_CASE_SUFFIX_PAIRS: [(&str, &str); 9] = [
("ay", "way"), ("ay", "yay"), ("ay", "hay"), ("erb", "ferb"), ("ancy", "fancy"), ("orange", "porange"), ("anana", "banana"), ("atin", "latin"), ("ust", "rust")
];
const SUFFIX_SPECIAL_CASE_SUFFIX_LOWER_UPPER_TUPLES: [(&str, &str, &str, &str); 9] = [
("ay", "way", "AY", "WAY"), ("ay", "yay", "AY", "YAY"), ("ay", "hay", "AY", "HAY"), ("erb", "ferb", "ERB", "FERB"),
("ancy", "fancy", "ANCY", "FANCY"), ("orange", "porange", "ORANGE", "PORANGE"),
("anana", "banana", "ANANA", "BANANA"), ("atin", "latin", "ATIN", "LATIN"), ("ust", "rust", "UST", "RUST"),
];
#[test]
fn test_translate_with_style() {
for pair in SUFFIX_SPECIAL_CASE_SUFFIX_PAIRS {
let suffix = pair.0;
let special_case_suffix = pair.1;
assert_eq!(translate_with_style("Hello world from the coolest Pig Latin translator!", suffix, special_case_suffix),
"Elloh".to_string() + suffix + " orldw" + suffix + " omfr" + suffix + " eth" + suffix + " oolestc" + suffix + " Igp" + suffix + " Atinl" + suffix + " anslatortr" + suffix + "!"
);
assert_eq!(translate_with_style("This library can translate any English text. It can even handle multiple sentences!", suffix, special_case_suffix),
"Isth".to_string() + suffix + " ibraryl" + suffix + " anc" + suffix + " anslatetr" + suffix + " any" + special_case_suffix + " English" + special_case_suffix + " extt" + suffix +
". It" + special_case_suffix + " anc" + suffix + " even" + special_case_suffix + " andleh" + suffix + " ultiplem" + suffix + " entencess" + suffix + "!"
);
}
}
#[test]
fn test_translate_with_style_edgecases() {
for pair in SUFFIX_SPECIAL_CASE_SUFFIX_PAIRS {
let suffix = pair.0;
let special_case_suffix = pair.1;
assert_eq!(translate_with_style("Let's try some edge cases. That is a contraction, as well as a word where the only vowel is y. Neat, all that works!", suffix, special_case_suffix),
"Etl".to_string() + suffix + "'s ytr" + suffix + " omes" + suffix + " edge" + special_case_suffix + " asesc" + suffix + ". Atth" + suffix + " is" + special_case_suffix + " a" +
special_case_suffix + " ontractionc" + suffix + ", as" + special_case_suffix + " ellw" + suffix + " as" + special_case_suffix + " a" + special_case_suffix + " ordw" + suffix +
" erewh" + suffix + " eth" + suffix + " only" + special_case_suffix + " owelv" + suffix + " is" + special_case_suffix + " y" + special_case_suffix + ". Eatn" + suffix + ", all" +
special_case_suffix + " atth" + suffix + " orksw" + suffix + "!"
);
assert_eq!(translate_with_style("What if a word has no vowels, like this: bcdfghjklmnpqrstvwxz", suffix, special_case_suffix),
"Atwh".to_string() + suffix + " if" + special_case_suffix + " a" + special_case_suffix + " ordw" + suffix + " ash" + suffix + " on" + suffix + " owelsv" + suffix + ", ikel" + suffix + " isth" + suffix + ": bcdfghjklmnpqrstvwxz" + suffix
);
assert_eq!(translate_with_style("Cool, so the heuristics make pretty good guesses with what they're fed!", suffix, special_case_suffix),
"Oolc".to_string() + suffix + ", os" + suffix + " eth" + suffix + " euristicsh" + suffix + " akem" + suffix + " ettypr" + suffix + " oodg" + suffix + " uessesg" + suffix + " ithw" + suffix + " atwh" + suffix + " eyth" + suffix + "'re edf" + suffix + "!"
);
assert_eq!(translate_with_style("Hello-world", suffix, special_case_suffix), "Elloh".to_string() + suffix + "-orldw" + suffix);
assert_eq!(translate_with_style("Hyphens-are-difficult-aren't-they?", suffix, special_case_suffix),
"Yphensh".to_string() + suffix + "-are" + special_case_suffix + "-ifficultd" + suffix + "-aren" + special_case_suffix + "'t-eyth" + suffix + "?"
);
}
}
#[test]
fn test_translate_with_style_uppercase() {
for pair in SUFFIX_SPECIAL_CASE_SUFFIX_LOWER_UPPER_TUPLES {
let suffix_lower = pair.0;
let special_case_suffix_lower = pair.1;
let suffix_upper = pair.2;
let special_case_suffix_upper = pair.3;
assert_eq!(translate_with_style("HELLO WORLD!", suffix_lower, special_case_suffix_lower),
"ELLOH".to_string() + suffix_upper + " ORLDW" + suffix_upper + "!"
);
assert_eq!(translate_with_style("ISN't THIS COOL?", suffix_lower, special_case_suffix_lower),
"ISN".to_string() + special_case_suffix_upper + "'t ISTH" + suffix_upper + " OOLC" + suffix_upper + "?"
);
assert_eq!(translate_with_style("What ABOUT a MIX?", suffix_lower, special_case_suffix_lower),
"Atwh".to_string() + suffix_lower + " ABOUT" + special_case_suffix_upper + " a" + special_case_suffix_lower + " IXM" + suffix_upper + "?"
);
assert_eq!(translate_with_style("Luke, I am your father!", suffix_lower, special_case_suffix_lower),//We don't want to capitalize single-letter words
"Ukel".to_string() + suffix_lower + ", I" + special_case_suffix_lower+ " am" + special_case_suffix_lower + " oury" + suffix_lower + " atherf" + suffix_lower + "!"
);
}
}
}
/* Benches */
#[cfg_attr(feature = "nightly-features-benches", cfg(test))]
#[cfg(feature = "nightly-features-benches")]
mod benches {
extern crate test;
use test::Bencher;
use super::*;
const PROJECT_DESCRIPTION: &str = "A simple Rust library to translate from English to Pig Latin!";
const LOREM_IPSUM: &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
#[bench]
fn way_project_description(b: &mut Bencher) {
b.iter(|| -> String { return translate(PROJECT_DESCRIPTION); });
}
#[bench]
fn yay_project_description(b: &mut Bencher) {
b.iter(|| -> String { return translate_yay(PROJECT_DESCRIPTION); });
}
#[bench]
fn hay_project_description(b: &mut Bencher) {
b.iter(|| -> String { return translate_hay(PROJECT_DESCRIPTION); });
}
#[bench]
fn ferb_project_description(b: &mut Bencher) {
b.iter(|| -> String { return translate_ferb(PROJECT_DESCRIPTION); });
}
#[bench]
fn way_lorem_ipsum(b: &mut Bencher) {
b.iter(|| -> String { return translate(LOREM_IPSUM); });
}
#[bench]
fn yay_lorem_ipsum(b: &mut Bencher) {
b.iter(|| -> String { return translate_yay(LOREM_IPSUM); });
}
#[bench]
fn hay_lorem_ipsum(b: &mut Bencher) {
b.iter(|| -> String { return translate_hay(LOREM_IPSUM); });
}
#[bench]
fn ferb_lorem_ipsum(b: &mut Bencher) {
b.iter(|| -> String { return translate_ferb(LOREM_IPSUM); });
}
}
Loading…
Cancel
Save