aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-14 12:48:58 +0900
committernsfisis <nsfisis@gmail.com>2026-06-14 12:48:58 +0900
commitc1070afe69f53b621adea232527080d2c922e1a9 (patch)
treebe125ece467c2d1d761cd9f8a606337f6e5233f4 /crates
parent4ace644474d3d0e5575d19616ce46ba7d521fc64 (diff)
downloadphp-shirabe-c1070afe69f53b621adea232527080d2c922e1a9.tar.gz
php-shirabe-c1070afe69f53b621adea232527080d2c922e1a9.tar.zst
php-shirabe-c1070afe69f53b621adea232527080d2c922e1a9.zip
refactor(pcre): consolidate duplicate preg_* shim helpers
The preg.rs shim had several near-duplicate functions: simple helpers re-implementing logic already covered by their full-featured `2` variants. Delegate or remove the redundant ones while preserving behavior, and migrate the affected callers: - preg_replace / preg_split now delegate to preg_replace2 / preg_split2 - preg_match_all_simple removed; its caller uses preg_match_all - preg_split_chars removed; its caller uses a char-boundary iterator - preg_match_offset removed; its callers use preg_match2 directly Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/shirabe-external-packages/src/symfony/console/formatter/output_formatter.rs6
-rw-r--r--crates/shirabe-external-packages/src/symfony/console/input/string_input.rs76
-rw-r--r--crates/shirabe-php-shim/src/preg.rs78
-rw-r--r--crates/shirabe/src/console/application.rs28
4 files changed, 78 insertions, 110 deletions
diff --git a/crates/shirabe-external-packages/src/symfony/console/formatter/output_formatter.rs b/crates/shirabe-external-packages/src/symfony/console/formatter/output_formatter.rs
index 27a74e6..0de90be 100644
--- a/crates/shirabe-external-packages/src/symfony/console/formatter/output_formatter.rs
+++ b/crates/shirabe-external-packages/src/symfony/console/formatter/output_formatter.rs
@@ -126,12 +126,10 @@ impl OutputFormatter {
.expect("preg_replace failed");
style.set_href(&url);
} else if r#match[0] == "options" {
- let mut options: Vec<Vec<String>> = vec![];
- shirabe_php_shim::preg_match_all_simple(
+ let mut options = shirabe_php_shim::preg_match_all(
"([^,;]+)",
&shirabe_php_shim::strtolower(&r#match[1]),
- &mut options,
- )?;
+ );
let options = shirabe_php_shim::array_shift(&mut options).unwrap_or_default();
for option in &options {
style.set_option(option);
diff --git a/crates/shirabe-external-packages/src/symfony/console/input/string_input.rs b/crates/shirabe-external-packages/src/symfony/console/input/string_input.rs
index 2d53f68..952a18e 100644
--- a/crates/shirabe-external-packages/src/symfony/console/input/string_input.rs
+++ b/crates/shirabe-external-packages/src/symfony/console/input/string_input.rs
@@ -5,7 +5,7 @@ use crate::symfony::console::input::argv_input::ArgvInput;
use crate::symfony::console::input::input_definition::InputDefinition;
use crate::symfony::console::input::input_interface::InputInterface;
use indexmap::IndexMap;
-use shirabe_php_shim::PhpMixed;
+use shirabe_php_shim::{CaptureKey, PhpMixed};
/// StringInput represents an input provided as a string.
///
@@ -54,52 +54,80 @@ impl StringInput {
continue;
}
- let mut m: Vec<String> = vec![];
- if shirabe_php_shim::preg_match_offset(r"/\s+/A", input, &mut m, 0, cursor) {
+ let mut m: IndexMap<CaptureKey, Option<String>> = IndexMap::new();
+ if shirabe_php_shim::preg_match2(r"/\s+/A", input, Some(&mut m), 0, cursor as usize)
+ .expect("invalid regex")
+ == 1
+ {
if token.is_some() {
tokens.push(token.take().unwrap());
}
- cursor += shirabe_php_shim::strlen(&m[0]);
- } else if shirabe_php_shim::preg_match_offset(
+ cursor +=
+ shirabe_php_shim::strlen(m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or(""));
+ } else if shirabe_php_shim::preg_match2(
&format!(r#"/([^="'\s]+?)(=?)({}+)/A"#, Self::REGEX_QUOTED_STRING),
input,
- &mut m,
+ Some(&mut m),
0,
- cursor,
- ) {
- let inner = shirabe_php_shim::substr(&m[3], 1, Some(-1));
+ cursor as usize,
+ )
+ .expect("invalid regex")
+ == 1
+ {
+ let inner = shirabe_php_shim::substr(
+ m[&CaptureKey::ByIndex(3)].as_deref().unwrap_or(""),
+ 1,
+ Some(-1),
+ );
let replaced =
shirabe_php_shim::str_replace_arr(&["\"'", "'\"", "''", "\"\""], "", &inner);
token = Some(format!(
"{}{}{}{}",
token.unwrap_or_default(),
- m[1],
- m[2],
+ m[&CaptureKey::ByIndex(1)].as_deref().unwrap_or(""),
+ m[&CaptureKey::ByIndex(2)].as_deref().unwrap_or(""),
shirabe_php_shim::stripcslashes(&replaced)
));
- cursor += shirabe_php_shim::strlen(&m[0]);
- } else if shirabe_php_shim::preg_match_offset(
+ cursor +=
+ shirabe_php_shim::strlen(m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or(""));
+ } else if shirabe_php_shim::preg_match2(
&format!(r"/{}/A", Self::REGEX_QUOTED_STRING),
input,
- &mut m,
+ Some(&mut m),
0,
- cursor,
- ) {
+ cursor as usize,
+ )
+ .expect("invalid regex")
+ == 1
+ {
token = Some(format!(
"{}{}",
token.unwrap_or_default(),
- shirabe_php_shim::stripcslashes(&shirabe_php_shim::substr(&m[0], 1, Some(-1)))
+ shirabe_php_shim::stripcslashes(&shirabe_php_shim::substr(
+ m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or(""),
+ 1,
+ Some(-1)
+ ))
));
- cursor += shirabe_php_shim::strlen(&m[0]);
- } else if shirabe_php_shim::preg_match_offset(
+ cursor +=
+ shirabe_php_shim::strlen(m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or(""));
+ } else if shirabe_php_shim::preg_match2(
&format!(r"/{}/A", Self::REGEX_UNQUOTED_STRING),
input,
- &mut m,
+ Some(&mut m),
0,
- cursor,
- ) {
- token = Some(format!("{}{}", token.unwrap_or_default(), m[1]));
- cursor += shirabe_php_shim::strlen(&m[0]);
+ cursor as usize,
+ )
+ .expect("invalid regex")
+ == 1
+ {
+ token = Some(format!(
+ "{}{}",
+ token.unwrap_or_default(),
+ m[&CaptureKey::ByIndex(1)].as_deref().unwrap_or("")
+ ));
+ cursor +=
+ shirabe_php_shim::strlen(m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or(""));
} else {
// should never happen
return Err(
diff --git a/crates/shirabe-php-shim/src/preg.rs b/crates/shirabe-php-shim/src/preg.rs
index e1b05b6..48b81ed 100644
--- a/crates/shirabe-php-shim/src/preg.rs
+++ b/crates/shirabe-php-shim/src/preg.rs
@@ -58,23 +58,12 @@ pub fn preg_match(pattern: &str, subject: &str, matches: &mut Vec<Option<String>
// Returns Some(result) on success, None on error.
pub fn preg_replace(pattern: &str, replacement: &str, subject: &str) -> Option<String> {
- let re = compile_php_pattern(pattern).ok()?;
- let mut out: Vec<u8> = Vec::new();
- let mut last = 0;
- for caps in re.captures_iter(subject) {
- let m = caps.get(0).unwrap();
- out.extend_from_slice(&subject.as_bytes()[last..m.start()]);
- php_replacement_expand(replacement, &caps, &mut out);
- last = m.end();
- }
- out.extend_from_slice(&subject.as_bytes()[last..]);
- Some(String::from_utf8_lossy(&out).into_owned())
+ preg_replace2(pattern, replacement, subject, -1, None)
}
// Returns Some(parts) on success, None on error.
pub fn preg_split(pattern: &str, subject: &str) -> Option<Vec<String>> {
- let re = compile_php_pattern(pattern).ok()?;
- Some(php_split_impl(&re, subject))
+ preg_split2(pattern, subject, -1, 0)
}
// PREG_PATTERN_ORDER: the outer vec is indexed by capture group, the inner by
@@ -95,29 +84,6 @@ pub fn preg_match_all(pattern: &str, subject: &str) -> Vec<Vec<String>> {
groups
}
-pub fn preg_match_all_simple(
- pattern: &str,
- subject: &str,
- matches: &mut Vec<Vec<String>>,
-) -> anyhow::Result<i64> {
- let re = compile_php_pattern(pattern)?;
- let group_count = re.captures_len();
- let mut groups: Vec<Vec<String>> = vec![Vec::new(); group_count];
- let mut count = 0i64;
- for caps in re.captures_iter(subject) {
- count += 1;
- for g in 0..group_count {
- groups[g].push(
- caps.get(g)
- .map(|m| m.as_str().to_string())
- .unwrap_or_default(),
- );
- }
- }
- *matches = groups;
- Ok(count)
-}
-
// PREG_SET_ORDER: the outer vec is indexed by match occurrence, the inner by
// capture group (a classic `$matches` row).
pub fn preg_match_all_set_order(
@@ -135,26 +101,6 @@ pub fn preg_match_all_set_order(
Ok(count)
}
-pub fn preg_match_offset(
- pattern: &str,
- subject: &str,
- matches: &mut Vec<String>,
- _flags: i64,
- offset: i64,
-) -> bool {
- let re = compile_php_pattern(pattern).unwrap_or_else(|e| panic!("invalid regex: {e}"));
- match re.captures_at(subject, offset as usize) {
- Some(caps) => {
- *matches = php_match_row(&caps);
- true
- }
- None => {
- matches.clear();
- false
- }
- }
-}
-
pub fn preg_match_groups(pattern: &str, subject: &str) -> Option<Vec<String>> {
let re = compile_php_pattern(pattern).ok()?;
let caps = re.captures(subject)?;
@@ -166,11 +112,6 @@ pub fn preg_grep(pattern: &str, input: &Vec<String>) -> Vec<String> {
input.iter().filter(|s| re.is_match(s)).cloned().collect()
}
-pub fn preg_split_chars(pattern: &str, subject: &str) -> Vec<String> {
- let re = compile_php_pattern(pattern).unwrap_or_else(|e| panic!("invalid regex: {e}"));
- php_split_impl(&re, subject)
-}
-
pub fn preg_match_all_offset_capture(
pattern: &str,
subject: &str,
@@ -551,21 +492,6 @@ fn php_replacement_group(bytes: &[u8]) -> (usize, usize) {
(group, consumed)
}
-// PHP `preg_split($pattern, $subject)` with no flags or limit: the text between
-// successive matches, including the leading and trailing pieces (which may be
-// empty). Zero-width matches split between every position.
-fn php_split_impl(re: &regex::Regex, subject: &str) -> Vec<String> {
- let mut result = Vec::new();
- let mut last = 0;
- for caps in re.captures_iter(subject) {
- let m = caps.get(0).unwrap();
- result.push(subject[last..m.start()].to_string());
- last = m.end();
- }
- result.push(subject[last..].to_string());
- result
-}
-
// Classic preg_match `$matches` row: index 0 is the full match, trailing
// unmatched groups are truncated and interior unmatched groups become "".
fn php_match_row(caps: &regex::Captures) -> Vec<String> {
diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs
index 00453f8..4be2f90 100644
--- a/crates/shirabe/src/console/application.rs
+++ b/crates/shirabe/src/console/application.rs
@@ -2703,17 +2703,33 @@ impl Application {
let mut line = String::new();
let mut offset = 0i64;
- let mut m: Vec<String> = Vec::new();
- while shirabe_php_shim::preg_match_offset(r"/.{1,10000}/u", &utf8_string, &mut m, 0, offset)
+ let mut m: indexmap::IndexMap<shirabe_php_shim::CaptureKey, Option<String>> =
+ indexmap::IndexMap::new();
+ while shirabe_php_shim::preg_match2(
+ r"/.{1,10000}/u",
+ &utf8_string,
+ Some(&mut m),
+ 0,
+ offset as usize,
+ )
+ .expect("invalid regex")
+ == 1
{
- offset += shirabe_php_shim::strlen(&m[0]);
+ let m0 = m[&shirabe_php_shim::CaptureKey::ByIndex(0)]
+ .as_deref()
+ .unwrap_or("");
+ offset += shirabe_php_shim::strlen(m0);
- for char in shirabe_php_shim::preg_split_chars(r"//u", &m[0]) {
+ let chunk = m0;
+ for char in chunk
+ .char_indices()
+ .map(|(i, c)| &chunk[i..i + c.len_utf8()])
+ {
// test if $char could be appended to current line
if shirabe_php_shim::mb_strwidth(&format!("{}{}", line, char), Some("utf8"))
<= width
{
- line.push_str(&char);
+ line.push_str(char);
continue;
}
// if not, push current line to array and make new line
@@ -2723,7 +2739,7 @@ impl Application {
" ",
shirabe_php_shim::STR_PAD_RIGHT,
));
- line = char;
+ line = char.to_string();
}
}