基于文件模式使用Scala重构并格式化文本文件
Let's walk through how to parse and reformat your messy input text into a clean, structured format using Scala. Here's a step-by-step approach tailored to your sample content:
1. Define Data Structures
First, let's model the data we're working with using case classes—this makes it easy to handle structured data once we parse the raw text:
case class Review( title: String, firstName: String, lastName: String, country: String, date: String, rating: Int, text: String, productType: String, productId: String ) case class Metadata( customerType: String, cabinFlown: String, route: String, dateFlown: String, seatComfort: String, cabinStaffService: String )
2. Write Parsing Logic with Regular Expressions
The input text has distinct patterns we can target with regex. Let's create patterns to match both the review entries and the metadata fields:
object TextFormatter { // Pattern for matching review entries (handles the core review structure) private val reviewPattern = """\"([^\"]+)\" (\w+) (\w+) \((\w+)\) (\d+\w+ \w+ \d{4}) (\d+) (.+?) (\w+) (\w+-\d+)""".r // Patterns for extracting metadata fields private val customerTypePattern = """Type Of Customer ([\w ]+)""".r private val cabinFlownPattern = """Cabin Flown (\w+)""".r private val routePattern = """Route (\w+ to \w+)""".r private val dateFlownPattern = """Date Flown (\w+ \d{4})""".r private val seatComfortPattern = """Seat Comfort (\d+)""".r private val cabinStaffServicePattern = """Cabin Staff Service (\d+)""".r def parseRawText(rawText: String): (List[Review], Metadata) = { // Extract all review entries from the raw text val reviews = reviewPattern.findAllMatchIn(rawText).map { m => Review( title = m.group(1), firstName = m.group(2), lastName = m.group(3), country = m.group(4), date = m.group(5), rating = m.group(6).toInt, text = m.group(7).trim, productType = m.group(8), productId = m.group(9) ) }.toList // Extract metadata fields (fallback to "Unknown" if a field is missing) val customerType = customerTypePattern.findFirstMatchIn(rawText).map(_.group(1)).getOrElse("Unknown") val cabinFlown = cabinFlownPattern.findFirstMatchIn(rawText).map(_.group(1)).getOrElse("Unknown") val route = routePattern.findFirstMatchIn(rawText).map(_.group(1)).getOrElse("Unknown") val dateFlown = dateFlownPattern.findFirstMatchIn(rawText).map(_.group(1)).getOrElse("Unknown") val seatComfort = seatComfortPattern.findFirstMatchIn(rawText).map(_.group(1)).getOrElse("Unknown") val cabinStaffService = cabinStaffServicePattern.findFirstMatchIn(rawText).map(_.group(1)).getOrElse("Unknown") val metadata = Metadata(customerType, cabinFlown, route, dateFlown, seatComfort, cabinStaffService) (reviews, metadata) } }
3. Format the Parsed Data into the Desired Output
Now that we have structured data, let's convert it into the clean, readable format you need:
def formatOutput(reviews: List[Review], metadata: Metadata): String = { // Format each review into the specified line structure val reviewsSection = reviews.map { review => s""""${review.title}" ${review.firstName} ${review.lastName} (${review.country}) |${review.date} ${review.rating} |${review.text} |${review.productType} ${review.productId} |""".stripMargin }.mkString("\n") // Format metadata into a clear, labeled section val metadataSection = s"""Type Of Customer: ${metadata.customerType} |Cabin Flown: ${metadata.cabinFlown} |Route: ${metadata.route} |Date Flown: ${metadata.dateFlown} |Seat Comfort: ${metadata.seatComfort} |Cabin Staff Service: ${metadata.cabinStaffService}""".stripMargin // Combine sections with a divider s"$reviewsSection\n---\n$metadataSection" }
4. Putting It All Together
To use this with your text file, read the file content, parse it, then format and output the result:
import scala.io.Source def main(args: Array[String]): Unit = { // Read raw text from your input file val rawText = Source.fromFile("your-input-file.txt").mkString // Parse into structured data val (reviews, metadata) = TextFormatter.parseRawText(rawText) // Generate formatted output val formattedText = formatOutput(reviews, metadata) // Print to console or write to a new file println(formattedText) // To write to a file: // import java.io.PrintWriter // new PrintWriter("formatted-output.txt") { write(formattedText); close() } }
Example Formatted Output
Using your sample input, the output will look like this:
"good service" Tom Martin (USA)
17th October 2015 4
Hi my name is Tom. I love boardgames.
Aircraft TXT-102"not bad" M Muller (Canada)
22nd September 2015 6
Hi I like boardgames.
Aircraft TXT-101Type Of Customer: Couple Leisure
Cabin Flown: FirstClass
Route: IND to CHI
Date Flown: September 2015
Seat Comfort: 12345
Cabin Staff Service: 12345
Quick Adjustments for Edge Cases
- If names have more than two parts (e.g., "Mary Ann Smith"), tweak the review regex to capture full names with
([\w ]+)instead of separate first/last groups. - If the input has inconsistent whitespace, add
\s+in the regex patterns to handle variable spacing between fields.
内容的提问来源于stack exchange,提问作者jOasis

