Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I got some text scraps with this structure

"Focal Plane: 198'  Active Aid to Navigation: Yes  *Latitude: 35.250 N  *Longitude: -75.529 W"

But some of them lack of parts like this

"Focal Plane: 198'  Active Aid to Navigation: Yes  *Longitude: -75.529 W"

Using regular expression matching, I want to extract all the info available, included getting a tag "NotAvailable" for missing data.,

I wrote this code, but it can't tell when a pattern does not match -- should the pattern in the middle not match, my code just skips it and goes on to the next pattern:

ptrFocal = "(?<=\\Focal Plane: )(.*?)(?=\\')";
ptrLat = "(?<=\\*Latitude: )(.*?)(?=[a-zA-Z])";
ptrLon = "(?<=\\*Longitude: )(.*?)(?=[a-zA-Z])";

r = 
  StringTrim /@ StringCases[text, 
    RegularExpression[ptrFocal <> "|" <> ptrLat <> "|" <> ptrLon]
  ];

I would want some pointers on how to do this.

EDIT:

The expected transformation of the example data I gave above is

{198, 32.250, -75.529}
{198, "NotAvailable", -75.529}
share|improve this question
    
What would be the desired result for each case? Is regex the only acceptable solution? –  Kuba May 4 at 7:40
    
I would "prefer" regex for the patterns, because I already know a little about it :) –  MHero May 4 at 8:16
1  
So you are not interested in W, N, S E? –  Kuba May 4 at 8:23
1  
@MHero: You can use StringPattern`PatternConvert[XXX] // InputForm where XXX is the Mathematica string pattern to see the regex it gets converted to, just FYI. Might give you some ideas on how to build your own if regex is mandatory. –  rasher May 4 at 8:59

3 Answers 3

up vote 3 down vote accepted
str1 = "Focal Plane: 198' Active Aid to Navigation: Yes *Latitude: \
35.250 N *Longitude: -75.529 W";

str2 = "Focal Plane: 198.12' Active Aid to Navigation: Yes \
*Longitude: -75.529 W"

With string patterns because I do not use regex :)

record[string_] := Map[
   StringCases[string, # ~~ x : NumberString :> x] /. {} -> "NotAvailable" &,
   {"Focal Plane: ", "Latitude: ", "Longitude: "}] // Flatten

record@str1

record@str2
{"198", "35.250", "-75.529"}
{"198.12", "NotAvailable", "-75.529"}

You can add ToExpression /@ StringCases[... if you need numbers not strings.

share|improve this answer

A variation of Kuba's method, using a single StringCases pass with post processing:

str2 = "Focal Plane: 198.12' Active Aid to Navigation: Yes *Longitude: -75.529 W"

fields = {"Focal Plane: ", "Latitude: ", "Longitude: "};

StringCases[str2, a : fields ~~ x : NumberString :> (a -> ToExpression[x])]
fields /. % /. _String :> "NotAvailable"
"Focal Plane: 198.12' Active Aid to Navigation: Yes *Longitude: -75.529 W"

{"Focal Plane: " -> 198.12, "Longitude: " -> -75.529}

{198.12, "NotAvailable", -75.529}
share|improve this answer

As requested, here is one approach using pure RegularExpression.

Another difference is the use of Internal`StringToDouble that is faster then ToExpression (velocity test here).

getFields[str_String]:=Module[{fields,r},
    fields = {"Focal Plane: ", "Latitude: ", "Longitude: "};    
    r=Map[StringCases[str,RegularExpression[#<>"((\\+|-)?\\d+(\\.\\d+)?)"]:>Internal`StringToDouble@"$1"]&,fields];
    r=Flatten[r/.{}-> Missing]
]

str1 = "Focal Plane: 198.23'  Active Aid to Navigation: Yes   *Longitude: -75.529 W";
str2 = "Focal Plane: 198.23'  Active Aid to Navigation: Yes  *Latitude: 35.250 N  *Longitude: -75.529 W";

getFields@str1
getFields@str2

{198.23, Missing, -75.529}

{198.23, 35.25`, -75.529}

share|improve this answer
2  
Thanks for reminding StringToDouble +1ed ofc. :) –  Kuba May 4 at 14:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.