2011-07-29 33 views
6

Ben tür aşağıdaki özelliklere sahip dizeleri kırmak için düzenli ifade ile gelip çalışırken takılıp:java regex bölünmüş dize

  1. tarafından Sınırlandırılmış'ı | (Boru) bireysel değer bir boru içeriyorsa karakter
  2. , bireysel bir değer ters eğik çizgi ile sona ererse, \ (ters eğik çizgi)
  3. ile kaçan ters eğik çizgiyle

Yani, örneğin, burada bazı dizeleri olduğunu ayrılmak istiyorum:

  1. One|Two|Three vermelidir: ["One", "Two", "Three"]
  2. One\|Two\|Three vermelidir: ["One|Two|Three"]
  3. One\\|Two\|Three vermelidir: ["One\", "Two|Three"]

Şimdi bir tek regex ile bu kadar bölünmüş nasıl?

GÜNCELLEME: Önceden önerdiğiniz gibi, bu normal ifadenin iyi bir uygulaması değildir. Ayrıca, regex çözümü sadece karakterlerin üzerinde yinelemekten daha yavaş büyüklükteki emirdir.

public static List<String> splitValues(String val) { 
    final List<String> list = new ArrayList<String>(); 
    boolean esc = false; 
    final StringBuilder sb = new StringBuilder(1024); 
    final CharacterIterator it = new StringCharacterIterator(val); 
    for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { 
     if(esc) { 
      sb.append(c); 
      esc = false; 
     } else if(c == '\\') { 
      esc = true; 
     } else if(c == '|') { 
      list.add(sb.toString()); 
      sb.delete(0, sb.length()); 
     } else { 
      sb.append(c); 
     } 
    } 
    if(sb.length() > 0) { 
     list.add(sb.toString()); 
    } 
    return list; 
} 
+1

en net yapalım. Ne istiyorsun: bölünmüş | ve dizeden kaldırın, \ | ve \ dizgeden \ n \ n \ n \ n \ n \ n \ n \ n \ n \ n \ split ve \ kaldır | birinci kısımdan ve ikinci kısımdan. Bunun bir regexp ile nasıl yapılacağını düşünüyorsunuz? Benim için tamamen farklı durumlar gibi görünüyor ... – user219882

+0

Sınırlayıcılarınızı değiştirmek mümkün mü? – Paul

+0

Sanırım siz haklısınız! Bu normal ifade için çok fazla olabilir. –

cevap

13

hüner split() yöntemi kullanmak değil: Ben karakterler üzerinde yineleme sona erdi. Bu, kaçan karakterleri algılamak için bir lookbehind kullanmaya zorlar ancak kaçanların kendiliğinden kaçtığında başarısız olur (keşfettiğiniz gibi). Sen belirteçleri yerine sınırlayıcı maç için, bunun yerine find() kullanmanız gerekir:

public static List<String> splitIt(String source) 
{ 
    Pattern p = Pattern.compile("(?:[^|\\\\]|\\\\.)+"); 
    Matcher m = p.matcher(source); 
    List<String> result = new ArrayList<String>(); 
    while (m.find()) 
    { 
    result.add(m.group().replaceAll("\\\\(.)", "$1")); 
    } 
    return result; 
} 

public static void main(String[] args) throws Exception 
{ 
    String[] test = { "One|Two|Three", 
        "One\\|Two\\|Three", 
        "One\\\\|Two\\|Three", 
        "One\\\\\\|Two" }; 
    for (String s :test) 
    { 
    System.out.printf("%n%s%n%s%n", s, splitIt(s)); 
    } 
} 

çıkışı:

One|Two|Three 
[One, Two, Three] 

One\|Two\|Three 
[One|Two|Three] 

One\\|Two\|Three 
[One\, Two|Three] 

One\\\|Two 
[One\|Two] 
+0

Bu etkileyici. Desenin nasıl çalıştığını açıklar mısınız? Hala düzenli ifadelerle mücadele ediyorum. – Paul

+0

WOW !! Bu tatlı! Regex'in hile yaptığını biliyordum :-) –

+0

Bu bir çekicilik gibi çalışıyor! Tekrar teşekkürler @Alan Moore! Şimdi nasıl tersini yaparsın? –