Results 1 to 6 of 6
  1. #1
    A5i19 is offline Member
    Join Date
    Nov 2009
    Posts
    7
    Rep Power
    0

    Default Help with my mess...using multiple delimiters and string splits...

    Alright what I need to do is take a text file that contains data formatted as so:
    5
    4 + 2 i
    -5 + -23 i
    etc...

    And what I need to do is read in these complex numbers into my program and then separate them so they will read as 4 2 so that I can compare the 2 integers to determine in which quadrants each complex number falls in.

    As of last night I was sure that I had managed to remove both the plus sign and i from each line, but when I ran my code today either the + or the i remains in each line, and I still cant figure out how to compare the two integers....any help would be greatly appreciated...

    my code so far is as follows: and as you can see its pretty much a mess as I do not really understand what I am doing...

    import java.io.File;
    import java.io.FileNotFoundException;
    import java.util.Scanner;
    import java.util.*;
    import java.lang.*;
    import java.util.regex.*;

    public class ComplexCatalog1b {
    public static void main(String[] args) {

    File file = new File("complex.txt");
    Scanner scanner = null;
    String part = null;

    try {

    //
    // Here we use the Scanner class to read file content line-by-line.
    //

    scanner = new Scanner(file);

    scanner.nextLine();

    while (scanner.hasNextLine()) {
    String line = scanner.nextLine();

    //
    // From the above line of code we got a line from the file
    // content. Now we want to split the line with "+" and the "i" as the
    // charater delimiters.
    //

    Scanner lineScanner = new Scanner(line);
    lineScanner.useDelimiter("\\+"); //sets delimiter "+"
    lineScanner.useDelimiter("i"); //sets delimiter "i"

    while (lineScanner.hasNext())
    {

    //
    // Get each splited data from the Scanner object and prints
    // the value.
    //

    part = lineScanner.next();

    System.out.print(part);

    }
    System.out.println();
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    }
    }

  2. #2
    travishein's Avatar
    travishein is offline Senior Member
    Join Date
    Sep 2009
    Location
    Canada
    Posts
    684
    Rep Power
    6

    Default

    if every line has only one complex number on it, could we separate the reading of the file part from the parsing of a line part. and the current way you do it with a scanner is good for doing that.

    while (scanner.hasNextLine()) {
    String line = scanner.nextLine();
    // TODO: make the part that parses this line into a complex expression into its own class
    }
    and have a second object to hold just complex data types (such as a separate file Complex.java) that has a method (maybe a constructor?) to take on a String parameter, and it uses what ever it can to parse this string (a single line from the original input) into a complex number.

    Java Code:
    public class Complex {
      public double real;
      public double imaginary;
      
      public Complex(String strComplex) {
        // TODO: parse this line into these real and imaginary fields.
      }
    }
    so, since a complex number can have
    - a signed real part
    - a signed imaginary part
    - both.
    - various permutations of spacing between the + sign, and the 'i'
    it is difficult (i think) to make a piece of code to handle all of the possible cases using just delimiters.

    I mean, if we always had a kind of different delimiter, such as using colin and equals sign
    key1 = value1 : key2 = value2 : key3 = value 3
    this can be handled by first tokenizing on " : " and then on " = "

    but here, because the + sign used to indicate the real and imaginary parts could also be used as the magnitude of the imaginary part, we would have to expect to see 1, 2, or 3 | signs

    1 + 2i
    +1 + 2i
    +1 + +2i

    What I have done in my example (below) is use a regular expression, rather than build out a full recursive decent parser.

    It turns out the complex numbers as you have shown in your example are matched by the regular expression
    Java Code:
    "(([+-]?[0-9\\.]+)\\s*\\+?\\s*)?(([+-]?[0-9\\.]+)\\s*i)?"
    it seems kind of hairy at first, but if we break it down into its pieces
    Java Code:
    [+-]?[0-9\\.]+
    will match an optional plus, or minus sign, followed by one or more digits, or decimal places, this is repeated for the real and imaginary pieces.
    so wrapping that in ( ) means to publish that as a 'group' (kind of like a node in a parse tree)
    Java Code:
    ([+-]?[0-9\\.]+)
    and then if there is a real part, attempt to consume the "+" that would be present if there was also an imaginary part.
    Java Code:
    \\s*\\+?\\s*
    where the \ s is the whitespace metacharacter in regular expresison, and the literal + sign 0 or 1 times.

    So in the full regular expression string, there are 4 groups, by the order of appearance of "(".
    and we would be interested in extracting group #2, if present, as the real part and group #4, if present, as the imaginary part.

    Java Code:
    Pattern p = Pattern.compile("(([+-]?[0-9\\.]+)\\s*\\+?\\s*)?(([+-]?[0-9\\.]+)\\s*i)?");
    Matcher matcher = p.matcher(strComplex);
    if (matcher.matches()) {
        String realPart = matcher.group(2);        
        String imaginaryPart = matcher.group(4);
    }
    and now, that we have the value and magnitude of both real and imaginary components, we can store them into the fields of the Complex class (i invented).

    Putting this all together,
    Java Code:
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     *Created on Nov 3, 2009
     */
    
    /**
     * @author thein
     *
     */
    public class ScanComplex {
      
      public static void main(String[] args) {
    
        String fileName = "complex.txt";
    
        // read file from command line parameters, if any
        if (args.length > 0) {
          fileName = args[0];
        }
        
        // try to open this file
        File file = new File(fileName);
        if (!file.exists()) {
          System.err.println("unable to find file to read from: " + fileName);
          System.exit(1);
        }
        
        BufferedReader reader = null;
        if ("-".equals(fileName)) {
          // when the command line parameter for file name was "-", try to read from standard input
          // (like unix programs do)
          reader = new BufferedReader(new InputStreamReader(System.in));
        }
        else {
          try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
          }
          catch (FileNotFoundException ex) {
            System.err.println("unable to find file to read from: " + fileName);
            System.exit(1);
          }
        }
        
        try {
          // now that we have the reader open, read a line until end of file
          String line = null;
          while ( (line = reader.readLine()) != null) {
            // with each line, have our complex data type parse it.
            
            Complex c = new Complex(line);
            
            System.out.println("read: " + c);
          }
        }
        catch (IOException ex) {
          System.err.println("error while reading input:" + ex);
        }
        finally {
          if (reader != null) {
            try {
              reader.close();
            } 
            catch (IOException ex) {
              // empty
            }
          }
        }
      }
    }
    
    class Complex {
      // fields public for convenience of accessing them, we could/should use get(), set() methods.
      public double real;
      public double imaginary;
      
      /**
       * creates an empty complex instance
       */
      public Complex() {
        
      }
      
      /**
       * Creates a complex instance initializing real and imaginary parts
       * @param r
       * @param im
       */
      public Complex(double r, double im) {
        this.real = r;
        this.imaginary = im;
      }
      
      /**
       * creates a complex instance by parsing a string representation of a complex number.
       * For example, +2 + -4i
       * Makes use of java regular expressions. Seems confusing at first, 
       * but is very elegant way to handle different combinations of variable text. 
       * @param strComplex
       * @return
       */
      public Complex(String strComplex) {
        // generally, for regular expressions, we define a pattern, then apply a matcher to test if a string matches the pattern.
        // a matched pattern can use "(" and ")" to indicate a 'group', which we can extract by asking for it by numerical index.
        // or test the presence/absence of it.
        
        // declare an array of patterns, in case
        Pattern[] patterns = new Pattern[] {
            Pattern.compile("(([+-]?[0-9\\.]+)\\s*\\+?\\s*)?(([+-]?[0-9\\.]+)\\s*i)?"),
        };
    
        boolean parsed = false;
        
        for (Pattern p : patterns) {
          Matcher matcher = p.matcher(strComplex);
          
          if (matcher.matches()) {
            String realPart = matcher.group(2);
            
            String imaginaryPart = matcher.group(4);
            
            //System.out.println("parsed real: " + realPart + " imaginary: " + imaginaryPart);
            
            if (realPart != null) {
              this.real = Double.parseDouble(realPart);
            }
            if (imaginaryPart != null) {
              this.imaginary = Double.parseDouble(imaginaryPart);
            }
            parsed = true;
            break;
          }     
        } // for each pattern
        
        if (!parsed)  {
          throw new IllegalArgumentException("unable to parse complex number: " + strComplex);
        }
      }
      
      public String toString() {
        return ("[" + real + " + " + imaginary + "i]");
      }
    }
    and running it with my complex.txt of the 3 values you provided,
    Java Code:
    $>java ScanComplex
    read: [5.0 + 0.0i]
    read: [4.0 + 2.0i]
    read: [-5.0 + -23.0i]

  3. #3
    A5i19 is offline Member
    Join Date
    Nov 2009
    Posts
    7
    Rep Power
    0

    Default Thank you

    thanks for the time and effort of do this, I dont entirely understand it but just being able to look at some different code is very helpful.

  4. #4
    A5i19 is offline Member
    Join Date
    Nov 2009
    Posts
    7
    Rep Power
    0

    Default Maybe you can help me understand this...

    In my code I wrote a segment that would hopefully take the first part of the complex number, for example, 1 + 2 i, and would convert it from a string to and integer.



    String realPart = lineScanner.next();
    int realValue = Integer.parseInt(realPart);

    What this does is it throws a :

    java.lang.NumberFormatException: For input string: "1" at java.lang.NumberFormatException.forInputString(Num berFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:458)
    at java.lang.Integer.parseInt(Integer.java:499)
    at ComplexScanner.main(ComplexScanner.java:56)

  5. #5
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

  6. #6
    travishein's Avatar
    travishein is offline Senior Member
    Join Date
    Sep 2009
    Location
    Canada
    Posts
    684
    Rep Power
    6

    Default

    hmm, for that, i wonder if the
    String realPart = lineScanner.next();
    int realValue = Integer.parseInt(realPart);
    if the lineScanner.next() is returning the "1 + 2i"

    try adding a system println between these
    Java Code:
    String realPart = lineScanner.next();
    System.out.println("realPart: `" + realPart + "`");
    int realValue = Integer.parseInt(realPart);
    note the use of the ticks to show whitespaces.

    also, another idea, the scanner supports fetching things based on regular expression Patterns. (the same Pattern thing i used before)

    for example, a variant of your code above to just fetch the real part from the scanner using a pattern for number only
    Java Code:
    String line = "1 + 2i";
        Scanner scanner = new Scanner(line);
        
        int realPart = 0;
        
        Pattern realPattern = Pattern.compile("[0-9]+");
        if (scanner.hasNext(realPattern)) {
          String strRealpart = scanner.next(realPattern);
          realPart = Integer.parseInt(strRealpart);
        }
        
        System.out.println("real part: " + realPart);
    where testing if the scanner contains the number thing as the next 'token' before fetching the number-only part (as enforced by using the regular expression "[0-9]+"

Similar Threads

  1. parsing multiple delimiters
    By meshhat in forum New To Java
    Replies: 3
    Last Post: 04-19-2009, 12:51 AM
  2. Read file delimiters
    By GraemeH in forum New To Java
    Replies: 4
    Last Post: 03-29-2009, 11:44 AM
  3. combine string[] into string like perl's join function
    By tekberg in forum Advanced Java
    Replies: 9
    Last Post: 02-23-2009, 01:05 PM
  4. Replies: 4
    Last Post: 07-07-2008, 01:32 PM
  5. Replies: 3
    Last Post: 12-17-2007, 02:35 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •