2010-06-15 7 views
4

Je dois diviser certaines informations à partir d'un astérisque délimité par des données.Manipulation de chaînes: Division de données délimitées

Format des données:

NAME*ADRESS LINE1*ADDRESS LINE2 

Règles:

1. Name should be always present 
2. Address Line 1 and 2 might not be 
3. There should be always three asterisks. 

échantillons:

MR JONES A ORTEGA*ADDRESS 1*ADDRESS2* 

Name: MR JONES A ORTEGA 
Address Line1: ADDRESS 1 
Address Line2: ADDRESS 2 

A PAUL*ADDR1** 
Name: A PAUL 
Address Line1: ADDR1 
Address Line2: Not Given 

Mon algo est:

1. Iterate through the characters in the line 
2. Store all chars in a temp variables until first * is found. Reject the data if no char is found before first occurence of asterisk. If some chars found, use it as the name. 
3. Same as step 2 for finding address line 1 and 2 except that this won't reject the data if no char is found 

Mon algo a l'air moche. Le code semble plus laid. La division en utilisant // * ne fonctionne pas non plus puisque le nom peut être remplacé par la ligne d'adresse 1 si les données étaient * Adresse 1 * Adresse2. Toute suggestion?

EDIT:

Essayez d'utiliser les données à l'exception des citations "-MS DEBBIE VERT * 1036 Pinewood CRES **"

+0

Pourriez-vous clarifier pourquoi vous ne pouvez pas utiliser split? Je n'ai pas tout à fait compris cette partie "nom peut être remplacé par adresse". – bezmax

+0

Si les données sont * Adresse 1 * Adresse2, la division créera deux index dans le tableau où l'index 0 aura la valeur de l'adresse 1 et l'index 2 aura la valeur de l'adresse 2. Comment puis-je valider le nom? Il n'y a pas de nom! –

+0

J'ai expliqué comment vous vous trompez dans ma réponse ci-dessous. – bezmax

Répondre

2

Vous pouvez utiliser le String[] split(String regex, int limit) comme suit:

String[] tests = { 
     "NAME*ADRESS LINE1*ADDRESS LINE2*", 
     "NAME*ADRESS LINE1**", 
     "NAME**ADDRESS LINE2*", 
     "NAME***", 
     "*ADDRESS LINE1*ADDRESS LINE2*", 
     "*ADDRESS LINE1**", 
     "**ADDRESS LINE2*", 
     "***", 
     "-MS DEBBIE GREEN*1036 PINEWOOD CRES**", 
    }; 
    for (String test : tests) { 
     test = test.substring(0, test.length() - 1); 
     String[] parts = test.split("\\*", 3); 
     System.out.printf(
      "%s%n Name: %s%n Address Line1: %s%n Address Line2: %s%n%n", 
      test, parts[0], parts[1], parts[2] 
     ); 
    } 

Cette impression (as seen on ideone.com):

NAME*ADRESS LINE1*ADDRESS LINE2* 
    Name: NAME 
    Address Line1: ADRESS LINE1 
    Address Line2: ADDRESS LINE2 

NAME*ADRESS LINE1** 
    Name: NAME 
    Address Line1: ADRESS LINE1 
    Address Line2: 

NAME**ADDRESS LINE2* 
    Name: NAME 
    Address Line1: 
    Address Line2: ADDRESS LINE2 

NAME*** 
    Name: NAME 
    Address Line1: 
    Address Line2: 

*ADDRESS LINE1*ADDRESS LINE2* 
    Name: 
    Address Line1: ADDRESS LINE1 
    Address Line2: ADDRESS LINE2 

*ADDRESS LINE1** 
    Name: 
    Address Line1: ADDRESS LINE1 
    Address Line2: 

**ADDRESS LINE2* 
    Name: 
    Address Line1: 
    Address Line2: ADDRESS LINE2 

*** 
    Name: 
    Address Line1: 
    Address Line2: 

-MS DEBBIE GREEN*1036 PINEWOOD CRES** 
    Name: -MS DEBBIE GREEN 
    Address Line1: 1036 PINEWOOD CRES 
    Address Line2: 

La raison de la "\\*" est parce que split prend une expression régulière , et * est un métacaractère regex, et puisque vous voulez qu'il signifie littéralement, il doit être échappé wit h \. Puisque \ lui-même est un caractère d'échappement de chaîne Java, pour obtenir un \ dans une chaîne, vous devez le doubler.

La raison du limit de 3 est que vous souhaitez que le tableau comporte 3 parties, y compris les chaînes vides finales.Un limit -less split supprime les chaînes vides à la fin par défaut.

La dernière * est supprimée manuellement avant l'exécution du split.

+0

Essayez d'utiliser les données sans les guillemets "-MS DEBBIE GREEN * 1036 PINEWOOD CRES **" –

+0

Il créerait 4 index pour l'échantillon donné ci-dessus en raison de la limite 4. Il ne semble pas satsfactory parce que je dois toujours ignorer la dernière indice. –

+1

Et quel est le problème avec ignorer le dernier index? Si vous ne voulez pas ignorer le dernier index, essayez d'utiliser la solution @andcoz fournie. Cependant, la performance serait pire car elle utilise une expression régulière plus complexe qui prend plus de temps à compiler. – bezmax

0
String myLine = "name*addr1*addr2*" 
String[] parts = myLine.split('\\*',4); 
for (String s : parts) { 
    System.out.println(s); 
} 

Sortie:

name 
addr1 
addr2 
(empty string) 

Si vous ne divisé sur "**addr2*" - vous obtiendrez tableau avec "", "", "addr2". Donc, je ne comprends pas pourquoi vous ne pouvez pas utiliser split.

De plus, si vous divisez "***" - vous obtiendrez un tableau de 4 éléments avec 4 chaînes vides.

Ici, vous obtenez un exemple, essayez d'exécuter ce code:

public void testStrings() { 
    String line = "part0***part3*part4****part8*"; 
    String[] parts = line.split("\\*"); 
    for (int i=0;i<parts.length;i++) { 
     System.out.println(String.format("parts[%d]: '%s'",i, parts[i])); 
    } 
} 

Le résultat sera:

parts[0]: 'part0' 
parts[1]: '' 
parts[2]: '' 
parts[3]: 'part3' 
parts[4]: 'part4' 
parts[5]: '' 
parts[6]: '' 
parts[7]: '' 
parts[8]: 'part8' 
+0

Je vois. La limite le rend acceptable. –

+0

Oui, car comme je l'ai écrit en haut de cette réponse, vous devriez utiliser: 'myLine.split ('\\ *', 3)' - 3 signifie qu'il y a 3 parties. – bezmax

+0

vous avez besoin de la limite de 4, sinon le dernier '*' sera inclus dans la 3ème partie. – polygenelubricants

-1

yourString.split("\\*"); devrait vous donner un tableau avec le nom, address1 et adresse2, où que adress1 et adresse2 peut être vide. Pour plus d'informations: here

+0

Non, ce ne serait pas. –

+0

Si les données sont * Adresse 1 * Adresse2, vous pouvez également utiliser la division. Vous obtiendrez un tableau avec 2 éléments au lieu de 3. Dans ce cas, vous savez que le tableau [0] contient le nom et l'adresse1. –

0

Vous pouvez utiliser regex pour cela. Par exemple:

String myInput="MR JONES A ORTEGA*ADDRESS 1*ADDRESS2*"; 

Pattern pattern = Pattern.compile("([^*]+)\\*([^*]*)\\*([^*]*)\\*"); 
Matcher matcher = pattern.matcher(myInput); 

if (matcher.matches()) { 
    String myName = matcher.group(1); 
    String myAddress1 = matcher.group(2); 
    String myAddress2 = matcher.group(3); 
    // ... 
} else { 
    // input does not match the pre-requisites 
} 
+1

Et si les données étaient pleines d'informations délimitées par des astérisques (*), cela ne serait-il pas illisible et déformé? –

+0

Je ne suis pas sûr de savoir quelle est votre question. Marmonner. La regex sera de plus en plus longue si vous ajoutez plus de champs et, éventuellement, la validation. Plus de puissance => plus de complexité. Si vous ajoutez un quatrième champ, par ex. un numéro de téléphone, vous pouvez également ajouter une validation en écrivant quelque chose comme "([^ *] +) \\ * ([^ *] *) \\ * ([^ *] *) \\ * ((+ \ d {2 } \ s) \ d +) * \\ * ". De toute évidence vous pouvez le commenter, vous pouvez écrire: "([^ *] +) \\ *"/* 1er champ: nom, obligatoire */+ "([^ *] *) \\ *"/* 2ème champ: adresse, optionnel */+ "([^ *] *) \\ *"/* ... * /. – andcoz

0

Une solution complète, la lecture du fichier en utilisant le scanner et les expressions régulières:

import java.io.*; 
import java.util.Scanner; 
import java.util.regex.Pattern; 

public class Test { 
    public static void main(String[] args) throws FileNotFoundException { 
     Scanner s = new Scanner(new File("data.txt")); 
     Pattern p = Pattern.compile("([^\\*]+)\\*([^\\*]*)\\*([^\\*]*)\\*"); 

     while (s.hasNextLine()) { 
      if (s.findInLine(p) == null) { 
       s.nextLine(); 
       continue; 
      } 

      System.out.println("Name: " + s.match().group(1)); 
      System.out.println("Addr1: " + s.match().group(2)); 
      System.out.println("Addr2: " + s.match().group(3)); 
      System.out.println(); 
     } 
    } 
} 

fichier d'entrée:

MR JONES A ORTEGA*ADDRESS 1*ADDRESS2* 
A PAUL*ADDR1** 
*No name*Addr 2* 
My Name*Some Addr*Some more addr* 

Sortie:

Name: MR JONES A ORTEGA 
Addr1: ADDRESS 1 
Addr2: ADDRESS2 

Name: A PAUL 
Addr1: ADDR1 
Addr2: 

Name: My Name 
Addr1: Some Addr 
Addr2: Some more addr 

Notez que la ligne sans nom ne correspond pas (selon Rule 1: Name should be always present). Si vous souhaitez toujours traiter ces lignes, modifiez simplement + dans les expressions régulières, en .

Les expressions régulières ([^\\*]*)\\* peuvent être lues comme suit: "Tout sauf un astérisque, zéro ou plusieurs fois, suivi d'un astérisque."

+1

Et si les données étaient pleines d'informations délimitées par des astérisques (*), cela ne serait-il pas illisible et déformé? –

+0

Non, ça irait très bien. – aioobe

+0

Pourquoi utilisez-vous "([^ \\ *] *) \\ *" au lieu de "([^ *] *) \\ *"? "*" n'a pas de signification particulière entre crochets. – andcoz