Как распознать первое слово после выражения с regex?

  1. Наиболее идиоматичным способом было бы просто использовать существующий ящик, в этом случае shellexpand ( github , crates.io ), кажется, делает что вы хотите:

    extern crate shellexpand; // 1.0.0
    
    #[test]
    fn test_shellexpand() {
        let home = std::env::var("HOME").unwrap();
        assert_eq!(shellexpand::tilde("~/foo"), format!("{}/foo", home));
    }
    
  2. В качестве альтернативы, вы можете попробовать его с dirs ( crates.io ). Вот эскиз:

    extern crate dirs; // 1.0.4
    
    use std::path::{Path, PathBuf};
    
    fn expand_tilde>(path_user_input: P) -> Option {
        let p = path_user_input.as_ref();
        if p.starts_with("~") {
            if p == Path::new("~") {
                dirs::home_dir()
            } else {
                dirs::home_dir().map(|mut h| {
                    if h == Path::new("/") {
                        // Corner case: `h` root directory;
                        // don't prepend extra `/`, just drop the tilde.
                        p.strip_prefix("~").unwrap().to_path_buf()
                    } else {
                        h.push(p.strip_prefix("~/").unwrap());
                        h
                    }
                })
            }
        } else {
            Some(p.to_path_buf())
        }
    }
    

    Примеры использования:

    #[test]
    fn test_expand_tilde() {
        // Should work on your linux box during tests, would fail in stranger
        // environments!
        let home = std::env::var("HOME").unwrap();
        let projects = PathBuf::from(format!("{}/Projects", home));
        assert_eq!(expand_tilde("~/Projects"), Some(projects));
        assert_eq!(expand_tilde("/foo/bar"), Some("/foo/bar".into()));
        assert_eq!(
            expand_tilde("~alice/projects"),
            Some("~alice/projects".into())
        );
    }
    

    Некоторые замечания:

    • Тип ввода P: AsRef имитирует то, что делает стандартная библиотека , Вот почему метод принимает все Path -подобные входные данные, такие как &str, &OsStr и &Path.
    • Path::new ничего не выделяет, оно указывает на те же байты, что и &str.
    • strip_prefix("~/").unwrap() никогда не должен потерпеть неудачу здесь, потому что мы проверили, что путь начинается с ~, а не просто ~. Единственным способом, которым это может быть, является то, что путь начинается с ~/ (из-за того, как определено starts_with).
18
задан JakeGould 15 June 2014 в 04:11
поделиться

4 ответа

Это походит на задание для lookbehinds, хотя необходимо знать, что не все regex разновидности поддерживают их. В Вашем примере:

(?<=\bipsum\s)(\w+)

Это будет соответствовать любой последовательности символов буквы, которая следует за "ipsum" в целом слово, сопровождаемое пространством. Это делает не соответствие "ipsum" само, Вы не должны волноваться о перевставке его в случае, например, замены.

, Поскольку я сказал, тем не менее, что некоторые разновидности (JavaScript, например) не поддерживают lookbehind вообще. Многие другие (большинство, на самом деле) только поддерживают "зафиксированную ширину" lookbehinds —, таким образом, Вы могли использовать этот пример, но не любой из операторов повторения. (Другими словами, (?<=\b\w+\s+)(\w+) не был бы работа.)

34
ответ дан 30 November 2019 в 07:18
поделиться

Некоторые из других респондентов предложили использовать regex, который не зависит от lookbehinds, но я думаю, что полный, рабочий пример необходим для понимания через. Идея состоит в том, что Вы соответствуете целой последовательности ("ipsum" плюс следующее слово) нормальным способом, затем используйте группу фиксации для изоляции части, которая интересует Вас. Например:

String s = "Lorem ipsum dolor sit amet, consectetur " +
    "adipiscing elit. Nunc eu tellus vel nunc pretium " +
    "lacinia. Proin sed lorem. Cras sed ipsum. Nunc " +
    "a libero quis risus sollicitudin imperdiet.";

Pattern p = Pattern.compile("ipsum\\W+(\\w+)");
Matcher m = p.matcher(s);
while (m.find())
{
  System.out.println(m.group(1));
}

Примечание, что это печатает и "печаль" и "Nunc". Чтобы сделать это с lookbehind версией, необходимо было бы сделать что-то hackish как:

Pattern p = Pattern.compile("(?<=ipsum\\W{1,2})(\\w+)");

Это находится в Java, который требует, чтобы lookbehind имел очевидную максимальную длину. Некоторые разновидности не имеют даже так большой гибкости, и конечно, некоторые не поддерживают lookbehinds вообще.

Однако крупнейшие трудные люди, кажется, имеют в их примерах, не с lookbehinds, а с границами слова. И David Kemp и ck, кажется, ожидают \b соответствовать пробелу после 'm', но он не делает; это соответствует положению (или граница) между 'm' и пространство.

Это - частая ошибка, один я даже видел повторенный в нескольких книгах и учебных руководствах, но граничная словом конструкция, \b, никогда не соответствует никаким символам. Это - утверждение нулевой ширины, как lookarounds и привязки (^, $, \z, и т.д.), и чему это соответствует, положение, которому или предшествует словесный символ и не сопровождает один, или сопровождает словесный символ и не предшествует один.

4
ответ дан 30 November 2019 в 07:18
поделиться

ipsum\b (\w*)

1
ответ дан 30 November 2019 в 07:18
поделиться

ipsum\b (.* РЕДАКТИРОВАНИЕ)\b

: хотя в зависимости от Вашей regex реализации, это могло быть голодно и найти все слова после ipsum

-1
ответ дан 30 November 2019 в 07:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: