read from stdin

master
Avril 4 years ago
parent ab97713013
commit d9ad1bafdf
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -6,6 +6,12 @@ edition = "2018"
# 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
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "unwind"
[features] [features]
perl = ["pcre"] perl = ["pcre"]

@ -1,56 +1,36 @@
#[cfg(not(feature = "perl"))] #![allow(dead_code)]
extern crate regex;
#[cfg(not(feature = "perl"))] mod re;
use regex::Regex; mod text;
#[cfg(not(feature = "perl"))] fn main() -> Result<(), Box<dyn std::error::Error>>
fn main() { {
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
if args.len() < 4 { if args.len() < 4 {
println!("Usage: {} <str> <regex> <group>", args[0]); println!("Usage: {} <str> <regex> <group>", args[0]);
println!("Pass `-' as `<str>' to read lines from stdin");
std::process::exit(1);
} else { } else {
let re = Regex::new(&args[2]).unwrap(); let re = re::Regex::compile(&args[2])?;
let text = &args[1]; let text = &args[1];
let group: usize = args[3].parse().expect("Invalid group number."); let group: usize = args[3].parse().expect("Invalid group number.");
match re.captures(&text) { if text == "-" {
text::stdin_lines(|text| -> Result<bool, re::Error> {
Some(groups) => { match re.exec(&text)? {
if group > groups.len() { Some(g) if g.len() > group => println!("{}", &g[group]),
eprintln!("Invalid group number."); _ => (),
} else {
println!("{}", groups.get(group).unwrap().as_str());
} }
} Ok(true)
None => (), })?;
} } else {
}
}
#[cfg(feature = "perl")]
extern crate pcre;
#[cfg(feature = "perl")]
use pcre::Pcre;
#[cfg(feature = "perl")]
fn main () {
let args: Vec<String> = std::env::args().collect();
if args.len() < 4 { match re.exec(&text)? {
println!("Usage: {} <str> <regex> <group>", args[0]); Some(g) if g.len() > group => println!("{}", &g[group]),
} else { _ => (),
let mut re = Pcre::compile(&args[2]).expect("Invalid regex."); }
let text = &args[1];
let group: usize = args[3].parse().expect("Invalid group number.");
match re.exec(&text) {
Some(m) if m.string_count() > group => println!("{}", m.group(group)),
_ => (),
} }
} }
Ok(())
} }

@ -0,0 +1,118 @@
#![allow(unused_imports)]
use std::{
error,
fmt::{
self,
Write,
},
sync::{
Arc,
Mutex,
}
};
pub type Groups = Vec<String>;
pub struct Regex
{
#[cfg(feature="perl")]
internal: Arc<Mutex<pcre::Pcre>>,
#[cfg(not(feature = "perl"))]
internal: regex::Regex,
}
#[derive(Debug)]
pub enum Error
{
Compile(String),
Execute,
Internal,
Unknown,
}
impl error::Error for Error{}
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "regex error: ")?;
match self {
Error::Compile(s) => write!(f, "compilation failed: {}", s),
Error::Execute => write!(f, "execution failed"),
Error::Internal => write!(f, "internal"),
_ => write!(f, "unknown"),
}
}
}
impl Regex {
pub fn compile(string: impl AsRef<str>) -> Result<Self, Error>
{
#[cfg(feature = "perl")]
return Ok(Self{internal: Arc::new(Mutex::new(pcre::Pcre::compile(string.as_ref())?))});
#[cfg(not(feature = "perl"))]
return Ok(Self{internal: regex::Regex::new(string.as_ref())?});
}
pub fn exec(&self, string: impl AsRef<str>) -> Result<Option<Groups>, Error>
{
#[cfg(feature = "perl")]
return {
let mut re = self.internal.lock().unwrap();
Ok(match re.exec(string.as_ref()) {
Some(m) => {
let len = m.string_count();
let mut output = Vec::with_capacity(len);
for i in 0..len {
output.push(m.group(i).to_owned());
}
Some(output)
},
None => None,
})
};
#[cfg(not(feature = "perl"))]
return {
Ok(match self.internal.captures(string.as_ref()) {
Some(m) => {
let mut output = Vec::with_capacity(m.len());
for i in 0..m.len() {
let ma = m.get(i).unwrap();
let mut op = String::with_capacity(ma.range().len());
write!(op, "{}", ma.as_str())?;
output.push(op);
}
Some(output)
},
None => None,
})
};
}
}
impl From<fmt::Error> for Error
{
fn from(_er: fmt::Error) -> Self
{
Self::Internal
}
}
#[cfg(not(feature = "perl"))]
impl From<regex::Error> for Error
{
fn from(er: regex::Error) -> Self
{
Self::Compile(format!("{}", er))
}
}
#[cfg(feature = "perl")]
impl From<pcre::CompilationError> for Error
{
fn from(er: pcre::CompilationError) -> Self
{
Self::Compile(format!("{}", er))
}
}

@ -0,0 +1,39 @@
use std::{
io::{
self,
Read,
},
error::Error,
marker::{
Send, Sync,
},
};
/// Read whole stdin
pub fn stdin() -> io::Result<String>
{
let mut buffer = String::new();
io::stdin().read_to_string(&mut buffer)?;
Ok(buffer)
}
/// Read each line with lambda
pub fn stdin_lines<E, F: FnMut(&str) -> Result<bool, E>>(mut callback: F) -> io::Result<usize>
where E: Into<Box<dyn Error + Send + Sync>>
{
let mut lines=0;
let mut input = String::new();
let stdin = io::stdin();
while match stdin.read_line(&mut input) {
Ok(0) => return Ok(lines),
Err(e) => return Err(e),
Ok(v) if input.as_bytes()[v-1] == b'\n' => callback(&input[..v]).or_else(|e| Err(io::Error::new(io::ErrorKind::Other, e)))?,
Ok(_) => callback(&input[..]).or_else(|e| Err(io::Error::new(io::ErrorKind::Other, e)))?,
} {
input.clear();
lines+=1;
}
Ok(lines)
}
Loading…
Cancel
Save