Вы можете использовать groupby()
и max()
, чтобы помочь здесь:
from itertools import groupby
with open('toy.txt') as f_input:
for key, group in groupby(f_input, lambda x: x[:2]):
print(max(group, key=lambda x: len(x)).strip())
Это отобразится:
ABCDEFGHIJKLMNO
CEST
DBTSFDEO
EOEUDNBNUW
EAEUDNBNUW
FGH
groupby()
работает, возвращая список совпадающих элементов на основе функции, в этом случае последовательные строки с теми же первыми двумя символами. Затем функция max()
берет этот список и возвращает элемент списка с самой длинной длиной.
Это сложно, потому что регулярное выражение может иметь несколько совпадений, и каждый захват может совпадать несколько раз в одном глобальном сопоставлении.
Может быть, что-то вроде этого (игровая площадка) :
fn main() {
let re = Regex::new(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})").unwrap();
let text = "2012-03-14";
let caps = re.captures(text).unwrap();
let dict: HashMap<&str, &str> = re
.capture_names()
.flatten()
.filter_map(|n| Some((n, caps.name(n)?.as_str())))
.collect();
println!("{:#?}", dict);
}
Это выводит:
{
"y": "2012",
"d": "14",
"m": "03"
}
Код прост, когда вы понимаете, что имена захвата не доступно от самого Match
, но от родителя Regex
. Вы должны сделать следующее:
capture_names()
, итерация будет равна Option<&str>
. flatten()
итерация, которая удалит None
и развернуть значения &str
. filter_map()
имена захвата в список кортежей (имя, значение) типа (&str, &str)
. filter
необходим для удаления отсутствующих снимков (благодаря @Anders). collect()
! Это просто работает, потому что HashMap<K, V>
реализует черту FromIterator<(K, V)>
, поэтому итератор (&str, &str)
собирает в HasMap<&str, &str>
. Если у вас есть несколько снимков, вы можете собрать их в список следующим образом:
let all: Vec<HashMap<&str, &str>> = re
.captures_iter("2012-01-12 , 2013-07-11 , 2014-09-14")
.map(|caps| {
re.capture_names()
.map(|o| o.and_then(|n| Some((n, caps.name(n)?.as_str()))))
.flatten()
.collect()
})
.collect();
println!("{:#?}", all);