2013-03-19 4 views
0

Le code que je regarde faire est un appel d'URL qui renvoie une chaîne composée de points de pour tracer un graphique. [14.1 (point), 1363649400 (horodatage UTC sera converti plus tard)]Quel serait le moyen le plus efficace d'analyser une chaîne dans une carte?

String = [14.1,1363649400],[14.4,1363650300],[14.6,1363651200],[15.1,1363652100],[14.3,1363653000],[14.2,1363653900],[14.8,1363654800]................ 

Le meilleur moyen semble être de supprimer les crochets et ensuite utiliser String.split().

Donc se demander si quelqu'un avait une meilleure idée sur la façon de convertir cette chaîne en carte, disons.

Répondre

1

Cela va prendre soin de l'analyse syntaxique et la construction de la carte. La carte sera également triée par horodatage.

final Matcher m = Pattern.compile("\\[(.*?),(.*?)\\]").matcher(input); 
final Map<Long, Double> points = new TreeMap<>(); 
while (m.find()) 
    points.put(Long.parseLong(m.group(2), Double.parseDouble(m.group(1))); 
1

Comme si:

points[] = string.substring(1, string.length()-1).split("],["); 

qui se traduirait par un tableau de

"1,3", "3,4" 
+0

' "1,3", "3,4"' d'où il vient? –

+0

@NikolayKuznetsov De l'entrée '" [1,3], [3,4] "'. –

+0

C'est juste un exemple de sortie. ["1,3"], ["3,4"] => "1,3"], ["3,4" => "1,3", "3,4" –

1

Créer une classe pour tenir vos objets de données:

private static final class Data { 

    private final BigDecimal point; 
    private final Date date; 

    public Data(final String point, final String date) { 
     this.point = new BigDecimal(point); 
     this.date = new Date(Long.parseLong(date)); 
    } 

    @Override 
    public String toString() { 
     return "Data{" + "point=" + point + ", date=" + date + '}'; 
    } 
} 

Parse maintenant la chaîne en utilisant un modèle regex, la construction des Data objets que vous allez. J'ai utilisé des coupleurs possessifs car le String est probablement assez long et vous ne voulez pas que le moteur express le fasse revenir en arrière en essayant de faire correspondre.

Le Data peut, comme ici, même analyser les String individuels aux types de données réels.

public static void main(String[] args) { 
    final String s = "[14.1,1363649400],[14.4,1363650300],[14.6,1363651200],[15.1,1363652100],[14.3,1363653000],[14.2,1363653900],[14.8,1363654800]"; 
    final Pattern p = Pattern.compile("\\[([^,]++),(\\d++)\\]"); 
    final Matcher matcher = p.matcher(s); 
    final Collection<Data> datas = new LinkedList<Data>(); 
    while (matcher.find()) { 
     datas.add(new Data(matcher.group(1), matcher.group(2))); 
    } 
    for (final Data data : datas) { 
     System.out.println(data); 
    } 
} 

Sortie:

Data{point=14.1, date=Fri Jan 16 19:47:29 GMT 1970} 
Data{point=14.4, date=Fri Jan 16 19:47:30 GMT 1970} 
Data{point=14.6, date=Fri Jan 16 19:47:31 GMT 1970} 
Data{point=15.1, date=Fri Jan 16 19:47:32 GMT 1970} 
Data{point=14.3, date=Fri Jan 16 19:47:33 GMT 1970} 
Data{point=14.2, date=Fri Jan 16 19:47:33 GMT 1970} 
Data{point=14.8, date=Fri Jan 16 19:47:34 GMT 1970} 

Évidemment, vous pouvez mettre ces Data dans un Map ou Set ou tout ce que vous convient.

0

L'utilisation d'une expression régulière ne semble pas être la meilleure approche, du moins pour moi. La performance de regex en java est, pour être honnête, vraiment mauvaise. J'écrirais moi-même un analyseur, qui ne prendrait que O(n) n étant la longueur de la chaîne.

Comment je le ferais:

public void splitSequence(String str) { 
       List<Double> lstPoint = new ArrayList<>(); 
    List<Long> lstTime = new ArrayList<>(); 
    char[] buf = new char[128]; 
    int i=0; 
    boolean isPoint = true; 
    for(Character c : str.toCharArray()) { 
     if(c == ',') { 
      if(isPoint) { 
       lstPoint.add(new Double(new String(buf,0,i))); 
       isPoint = false; 
      } 
      else { 
       lstTime.add(Long.parseLong(new String(buf,0,i))); 
       isPoint = true; 
      } 
      buf = new char[128]; 
      i=0; 
     } else if(!(c == '[' || c == ']')) { 
      buf [i++] = c; 
     } 
    } 
    } 
//usage 
splitSequence("[14.1,1363649400],[14.4,1363650300],[14.6,1363651200],[15.1,1363652100],[14.3,1363653000],[14.2,1363653900],[14.8,1363654800]"); 
+0

Je pense que les performances de regex dépendent uniquement de la façon dont l'expression régulière est écrite - c'est-à-dire combien de retour en arrière le moteur doit faire. Si vous écrivez regex correctement et qu'il y a peu ou pas de backtracking (en utilisant des matchers possessifs, etc.) alors la performance sera aussi O (n). S'il y a des irrégularités dans l'entrée, vos deux listes seront mal alignées et les données seront corrompues. –

+0

L'utilisation de O (n) de DFA est plus que possible, c'est en fait facile. Mais est-ce ainsi que Java l'implémente? Je ne suis pas vraiment sûr, mais j'ai entendu dire que ce n'est pas ... Comme l'a dit Einstein, la moitié de la connaissance est pire que de ne pas savoir du tout. –

+0

Non, Java est NFA. Mais l'utilisation du quantificateur possessif (par exemple ++ plutôt que +) empêche le moteur de revenir en arrière. Les quantificateurs possessifs saisissent tout ce qui correspond et ne le rendent pas, ce qui permet une analyse beaucoup plus rapide. –

Questions connexes