Questo è come la soluzione Java 9 sarà molto probabilmente simile:
Matcher m = Pattern.compile("name: '(.+)'").matcher("");
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> m.reset(line).results().limit(1))
.forEach(mr -> System.out.println(mr.group(1)));
}
Si utilizza il metodo Matcher.results()
che restituisce un flusso di tutte le partite. La combinazione di un flusso di linee con un flusso di corrispondenze tramite flatMap
ci consente di elaborare tutte le corrispondenze di un file. Poiché il codice originale elabora solo la prima corrispondenza di una riga, ho semplicemente aggiunto un valore limit(1)
alle corrispondenze di ogni riga per ottenere lo stesso comportamento.
Purtroppo, questa funzione non è presente in Java 8, tuttavia, furtivamente in prossime versioni aiuta a farsi un'idea di come una soluzione provvisoria può apparire come:
Matcher m = Pattern.compile("name: '(.+)'").matcher("");
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> m.reset(line).find()? Stream.of(m.toMatchResult()): null)
.forEach(mr -> System.out.println(mr.group(1)));
}
per semplificare la creazione sub-stream, questa soluzione utilizza che solo la prima corrispondenza è destinata e crea un singolo flusso di elementi in primo luogo.
ma nota che con il modello della domanda 'name: '(.+)'
non importa se limitiamo il numero di corrispondenze .+
sarà avidamente corrispondere tutti i caratteri fino all'ultimo follow-up '
della linea, in modo da un altro match è impossibile. Le cose sono diverse quando si utilizza un quantificatore riluttante come con name: '(.*?)'
che consuma fino al prossimo '
piuttosto che l'ultima uno o vieta di saltare passato '
esplicitamente, come con name: '([^']*)'
.
Le soluzioni sopra uso condiviso Matcher
che funziona bene con l'utilizzo thread singolo (e questo è improbabile beneficiare mai dall'elaborazione parallela). Ma se si vuole essere sul sicuro filo, si può solo condividere un Pattern
e creare un Matcher
invece di chiamare m.reset(line)
:
Pattern pattern = Pattern.compile("name: '(.*)'");
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> pattern.matcher(line).results().limit(1))
.forEach(mr -> System.out.println(mr.group(1)));
}
resp. con Java 8
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> {Matcher m=pattern.matcher(line);
return m.find()? Stream.of(m.toMatchResult()): null;})
.forEach(mr -> System.out.println(mr.group(1)));
}
che non è così conciso a causa dell'introduzione di una variabile locale.Ciò può essere evitato un map
operazione precedente, ma quando siamo a questo punto, fintanto che solamente la testa per una singola partita per linea, non abbiamo bisogno un flatMap
poi:
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.map(pattern::matcher).filter(Matcher::find)
.forEach(m -> System.out.println(m.group(1)));
}
Poiché ogni Matcher
è usato esattamente una volta, in modo non interferente, la sua natura mutevole non fa male qui e una conversione in un immutabile MatchResult
diventa inutile.
Tuttavia, queste soluzioni non possono essere scalati per elaborare più corrispondenze per riga, se diventa mai necessario ...
La fase pipeline 'map (p :: matcher)' crea un nuovo oggetto 'Matcher' per ogni riga in lettura. Per file estremamente grandi, questa può essere una fonte di inefficienza. Invece, un oggetto 'Matcher' riutilizzabile può essere creato, e' .map (matcher :: reset) 'può essere usato per mappare dalla linea appena letto nel' matcher' riutilizzabile, come mostrato [qui] (https://stackoverflow.com/a/47877960/3690024). Il riutilizzo di oggetti stateful nelle pipeline dei flussi viola tutti i tipi di regole, quindi lo consiglierei solo se stai leggendo file di grandi dimensioni e ne crei un collo di bottiglia. – AJNeufeld