2015-05-08 20 views
7

Ho un albero di analisi che include alcune informazioni. Per estrarre le informazioni di cui ho bisogno, sto usando un codice che divide la stringa in base alla barra (/), ma questo non è un codice perfetto. Spiego più dettagli qui:Espressione regolare da dividere con barra diretta

Avevo usato questo codice in un altro progetto in precedenza e questo ha funzionato perfettamente. Ma ora gli alberi di analisi del mio nuovo set di dati sono più complicati e il codice a volte prende decisioni sbagliate.

Il parse albero è qualcosa di simile:

(TOP~did~1~1 (S~did~2~2 (NPB~I~1~1 I/PRP) (VP~did~3~1 did/VBD not/RB (VP~read~2~1 read/VB (NPB~article~2~2 the/DT article/NN ./PUNC.))))) 

Come si vede, le foglie dell'albero sono le parole a destra prima del slash. Per ottenere queste parole, ho usato questo codice prima:

parse_tree.split("/"); 

Ma ora, nei miei nuovi dati, vedo casi come questi:

1) (TOP Source/NN http://www.alwatan.com.sa/daily/2007-01-31/first_page/first_page01.htm/X ./.)

dove ci sono più tagli dovuti agli indirizzi dei siti Web (in questo caso, solo l'ultima barra è il separatore della parola).

2) (NPB~sister~2~2 Your/PRP$ sister/NN //PUNC:)

Quando la barra è una parola stessa.

Potresti per favore aiutarmi a sostituire la mia attuale espressione regolare con un'espressione che può gestire questi casi?

Per riassumere ciò di cui ho bisogno, direi che ho bisogno di un'espressione regolare che può essere suddivisa in base alla barra, ma deve essere in grado di gestire due eccezioni: 1) se c'è un indirizzo del sito web, deve essere diviso basato sull'ultima barra. 2) Se ci sono due barre consecutive, deve dividere in base al secondo split (e la prima barra NON deve essere considerata come un separatore, è una WORD).

+0

Potrebbe cercare di chiarire la tua domanda ? Vuoi dividere per "/" a meno che non ci sia un indirizzo Web? – Praeterii

+0

È possibile scegliere quale simbolo separatore utilizzare nella rappresentazione dell'albero di analisi? potrebbe essere più facile/più gestibile da usare ad es. '§' invece di'/'. – collapsar

+0

@Praeterii Grazie mille per la risposta. Ho aggiunto un sommario alla mia domanda che chiarisce ciò di cui ho bisogno. – user1419243

risposta

1

Dovresti essere in grado di utilizzare un lookbehind negativo con un'espressione regolare. Questo avrebbe bisogno di un campione più grande di ingressi per essere sicuri, ma sembra funzionare per i vostri due casi:

String pattern = "(?<![\\:\\/])\\/"; 

    String s1 = "(TOP Source/NN http://www.alwatan.com.sa/daily/2007-01-31/first_page/first_page01.htm/X ./.)"; 
    List<String> a = (List<String>) Arrays.asList(s1.split(pattern)); 

    System.out.println("first case:"); 
    System.out.println(a.stream().map(i->i.toString()).collect(Collectors.joining(",\n"))); 
    System.out.println("\n"); 

    String s2 = "(NPB~sister~2~2 Your/PRP$ sister/NN //PUNC:)"; 
    a = (List<String>) Arrays.asList(s2.split(pattern)); 
    System.out.println("second case"); 
    System.out.println(a.stream().map(i->i.toString()).collect(Collectors.joining(",\n"))); 

Questo uscite:

first case: 
(TOP Source, 
NN http://www.alwatan.com.sa, 
daily, 
2007-01-31, 
first_page, 
first_page01.htm, 
X ., 
.) 


second case 
(NPB~sister~2~2 Your, 
PRP$ sister, 
NN , 
/PUNC:) 
3

ho raggiunto quello che avete richiesto seguendo questo articolo:

http://www.rexegg.com/regex-best-trick.html

Giusto per riassumere, qui è la strategia su tutti:

prima, è necessario creare un Regex in questo formato:

NotThis | NeitherThis | (IWantThis) 

Dopo di che, il vostro gruppo di cattura $ 1 contiene solo le barre a cui sei interessato eseguire le spaccature.

È quindi possibile sostituirli con qualcosa di meno probabile che si verifichi, e dopo che si esegue la divisione in questo termine sostituito.

Quindi, avendo in mente questa strategia, ecco il codice:

Regex:

\\/(?=\\/)|(?:http:\\/\\/)?www[\\w\\.\\/\\-]*(?=\\/)|(\\/) 

Spiegazione:

NotThis termine sarebbe barre doppie con lookAhead (prendere solo prima barra)

\\/(?=\\/) 

Né questo termine è solo un controllo di base con un URL okahead di non catturare l'ultimo termine \/

(?:http:\\/\\/)?www[\\w\\.\\/\\-]*(?=\\/) 

IWantThis è semplicemente la barra:

(\\/) 

Nel codice Java si può mettere insieme tutto questo facendo qualcosa di simile:

Pattern p = Pattern.compile("\\/(?=\\/)|(?:http:\\/\\/)?www[\\w\\.\\/\\-]*(?=\\/)|(\\/)"); 

Matcher m = p.matcher("(TOP~did~1~1 (S~did~2~2 (NPB~I~1~1 I/PRP) (VP~did~3~1 did/VBD not/RB (VP~read~2~1 read/VB (NPB~article~2~2 the/DT article/NN ./PUNC.)))))\n(TOP Source/NN http://www.alwatan.com.sa/daily/2007-01-31/first_page/first_page01.htm/X ./.)\n(NPB~sister~2~2 Your/PRP$ sister/NN //PUNC:)"); 
StringBuffer b= new StringBuffer(); 
while (m.find()) { 
    if(m.group(1) != null) m.appendReplacement(b, "Superman"); 
    else m.appendReplacement(b, m.group(0)); 
} 
m.appendTail(b); 
String replaced = b.toString(); 
System.out.println("\n" + "*** Replacements ***"); 
System.out.println(replaced); 

String[] splits = replaced.split("Superman"); 
System.out.println("\n" + "*** Splits ***"); 
for (String split : splits) System.out.println(split); 

Uscita:

*** Replacements ***                                             
(TOP~did~1~1 (S~did~2~2 (NPB~I~1~1 ISupermanPRP) (VP~did~3~1 didSupermanVBD notSupermanRB (VP~read~2~1 readSupermanVB (NPB~article~2~2 theSupermanDT articleSupermanNN .SupermanPUNC.)))))  
(TOP SourceSupermanNN http://www.alwatan.com.sa/daily/2007-01-31/first_page/first_page01.htmSupermanX .Superman.)                      
(NPB~sister~2~2 YourSupermanPRP$ sisterSupermanNN /SupermanPUNC:)                                   

*** Splits ***                                               
(TOP~did~1~1 (S~did~2~2 (NPB~I~1~1 I                                         
PRP) (VP~did~3~1 did                                             
VBD not                                                
RB (VP~read~2~1 read                                             
VB (NPB~article~2~2 the                                            
DT article                                                
NN .                                                 
PUNC.)))))                                              
(TOP Source                                               
NN http://www.alwatan.com.sa/daily/2007-01-31/first_page/first_page01.htm                                
X .                                                 
.) 
(NPB~sister~2~2 Your                                             
PRP$ sister                                               
NN/
PUNC:) 
0

Filtra i risultati più a non includere regex riscontro di sotto dei quali corrisponde a qualsiasi URL HTTP/HTTPS/FTP è possibile includere tanto protocolli come ti piace

(?<protocol>http(s)?|ftp)://(?<server>([A-Za-z0-9-]+\.)*(?<basedomain>[A-Za-z0-9-]+\.[A-Za-z0-9]+))+ ((/?)(?<path>(?<dir>[A-Za-z0-9\._\-]+)))* 

and then match instances of multiple slashes with (/)+ 
the'+' here is a greedy match which means it will match as many consecutive slashes as it can whether it be // // or // 

Spero che questo aiuti

Problemi correlati