如何在Java中将指定格式文本行解析为自定义User对象?
Hey there! Parsing that structured text line into your User class is a perfect job for regular expressions—they’re ideal for consistent, pattern-based input. Here’s the cleanest, most maintainable approach I’d recommend:
We’ll use a pre-compiled regex to match the input format, extract each component, validate the structure, and map everything to the User object. This approach is efficient, easy to debug, and handles edge cases gracefully.
Step 1: Define the Regex Pattern
The input follows a strict format:
- Quoted full name (e.g.,
"Adam Xin") - Quoted location path (country/province/city, e.g.,
"Canada/British Columbia/Vancouver") - Decimal value (e.g.,
2.110)
The regex pattern to match this is:
^"([^"]+)" "([^"]+)" (\d+\.\d+)$
Pattern Explanation:
^: Start of the line"([^"]+)": Capture everything inside the first pair of quotes (the full name)" ": Match the space between the two quoted segments"([^"]+)": Capture everything inside the second pair of quotes (the location path)(\d+\.\d+): Capture the decimal value (one or more digits, a dot, then one or more digits)$: End of the line
Step 2: Full Implementation Code
First, we’ll add setter methods to your User class (since the fields are private, we need a way to populate them). Then we’ll create a parser class with the regex logic:
import java.util.regex.Matcher; import java.util.regex.Pattern; // Parser class with reusable, pre-compiled regex public class UserLineParser { // Precompile regex once for performance (avoids recompiling on every parse) private static final Pattern USER_INPUT_PATTERN = Pattern.compile("^\"([^\"]+)\" \"([^\"]+)\" (\\d+\\.\\d+)$"); public static User parseUserFromLine(String inputLine) throws IllegalArgumentException { // Validate input isn't null/blank if (inputLine == null || inputLine.isBlank()) { throw new IllegalArgumentException("Input line cannot be null or empty"); } Matcher matcher = USER_INPUT_PATTERN.matcher(inputLine); if (!matcher.matches()) { throw new IllegalArgumentException("Input doesn't match expected format: " + inputLine); } // Extract and split full name into first/last String fullName = matcher.group(1); String[] nameSegments = fullName.split(" ", 2); // Split on first space to handle middle names if needed if (nameSegments.length != 2) { throw new IllegalArgumentException("Full name must include first and last name: " + fullName); } String firstName = nameSegments[0]; String lastName = nameSegments[1]; // Extract and split location path into country/province/city String locationPath = matcher.group(2); String[] locationSegments = locationPath.split("/"); if (locationSegments.length != 3) { throw new IllegalArgumentException("Location must follow country/province/city format: " + locationPath); } String country = locationSegments[0]; String province = locationSegments[1]; String city = locationSegments[2]; // Parse the decimal rValue Double rValue; try { rValue = Double.parseDouble(matcher.group(3)); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid decimal value: " + matcher.group(3), e); } // Populate and return the User object User user = new User(); user.setFirstName(firstName); user.setLastName(lastName); user.setCountry(country); user.setProvince(province); user.setCity(city); user.setRValue(rValue); return user; } } // Updated User class with setters (and optional toString for debugging) class User { private String firstName; private String lastName; private String country; private String province; private String city; private Double rValue; // Setter methods public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setCountry(String country) { this.country = country; } public void setProvince(String province) { this.province = province; } public void setCity(String city) { this.city = city; } public void setRValue(Double rValue) { this.rValue = rValue; } // Optional: For easy debugging @Override public String toString() { return "User{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", country='" + country + '\'' + ", province='" + province + '\'' + ", city='" + city + '\'' + ", rValue=" + rValue + '}'; } }
Step 3: Usage Example
To test the parser, use this simple main method:
public class Main { public static void main(String[] args) { String sampleInput = "\"Adam Xin\" \"Canada/British Columbia/Vancouver\" 2.110"; try { User parsedUser = UserLineParser.parseUserFromLine(sampleInput); System.out.println("Parsed User: " + parsedUser); } catch (IllegalArgumentException e) { System.err.println("Parsing failed: " + e.getMessage()); } } }
Output:
Parsed User: User{firstName='Adam', lastName='Xin', country='Canada', province='British Columbia', city='Vancouver', rValue=2.11}
Key Advantages of This Approach
- Performance: Precompiling the regex avoids redundant processing on every parse.
- Validation: Strict checks ensure the input matches the expected format before populating the User object.
- Maintainability: The regex and split logic are easy to adjust if the input format changes (e.g., adding middle names or more location levels).
- Error Handling: Clear, descriptive exceptions make debugging parsing failures straightforward.
Edge Case Considerations
- If full names might include middle names, the
split(" ", 2)ensures everything after the first space is treated as the last name (adjustable if needed). - If the rValue could be an integer (e.g.,
5instead of5.0), modify the regex to(\d+(\.\d+)?)to allow both integer and decimal values. - If location paths might contain escaped quotes (unlikely per your example), you’d need to adjust the regex to handle escaped characters.
内容的提问来源于stack exchange,提问作者BrownTownCoder

