Browse Source

星宿补充完成,增加相位差显示

master
hejl 1 week ago
parent
commit
b321cd214d
  1. 1207
      win_text_editor/lib/modules/pdf_parse/controllers/pdf_parse_controller.dart
  2. 3
      win_text_editor/lib/modules/pdf_parse/controllers/pdf_parse_parse_controller.dart
  3. 106
      win_text_editor/lib/modules/pdf_parse/services/content_deal_service.dart
  4. 305
      win_text_editor/lib/modules/pdf_parse/services/excel_data_adjustment_service.dart
  5. 434
      win_text_editor/lib/modules/pdf_parse/services/excel_data_adjustment_service_backup.dart
  6. 32
      win_text_editor/lib/modules/pdf_parse/services/excel_deal_service.dart
  7. 21
      win_text_editor/lib/modules/pdf_parse/services/relationship_calculator_service.dart
  8. 91
      win_text_editor/lib/modules/pdf_parse/widgets/pdf_parse_output.dart

1207
win_text_editor/lib/modules/pdf_parse/controllers/pdf_parse_controller.dart

File diff suppressed because it is too large Load Diff

3
win_text_editor/lib/modules/pdf_parse/controllers/pdf_parse_parse_controller.dart

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@

106
win_text_editor/lib/modules/pdf_parse/services/content_deal_service.dart

@ -18,7 +18,8 @@ class _TableData { @@ -18,7 +18,8 @@ class _TableData {
class ContentDealService {
static const String _logTag = 'ContentDealService';
static const int _maxDisplayLines = 100;
static const int _maxDisplayLines = 100; //
// _maxDataLines Excel导出不受限制
// Content classification identifiers
static const String rawTextSection = '原始文本';
@ -43,29 +44,24 @@ class ContentDealService { @@ -43,29 +44,24 @@ class ContentDealService {
};
Map<String, String> processPdfContent(String allText) {
// Process raw text display
//
// UI卡顿
// Process raw text display ()
final rawLines = allText.split('\n');
final rawContent =
rawLines.length > _maxDisplayLines
? '${rawLines.take(_maxDisplayLines).join('\n')}\n<<<剩余内容未显示>>>'
: allText;
// Extract and process all tables with their dates
// Extract and process all tables with their dates ()
final tables = _extractTablesWithDates(allText);
final processedTables =
List.generate(tables.length, (index) {
final t = tables[index];
return _processTable(
t.content,
t.year,
t.month,
emitHeader: index == 0, //
);
})
.where((s) => s.isNotEmpty)
.join('\n'); //
final processedTables = List.generate(tables.length, (index) {
final t = tables[index];
return _processTable(t.content, t.year, t.month, emitHeader: index == 0);
}).where((s) => s.isNotEmpty).join('\n');
// Limit processed content display
// Limit processed content display ()
final processedLines = processedTables.split('\n');
final limitedProcessedContent =
processedLines.length > _maxDisplayLines
@ -78,6 +74,8 @@ class ContentDealService { @@ -78,6 +74,8 @@ class ContentDealService {
};
}
// _limitTextLines
List<_TableData> _extractTablesWithDates(String rawText) {
final lines = rawText.split('\n');
final tables = <_TableData>[];
@ -88,11 +86,20 @@ class ContentDealService { @@ -88,11 +86,20 @@ class ContentDealService {
for (final line in lines) {
// Check for new table header
final dateMatch = RegExp(r'^([A-Z]+)\s+(\d{4})\s+00:00 UT').firstMatch(line);
final dateMatch = RegExp(
r'^([A-Z]+)\s+(\d{4})\s+00:00 UT',
).firstMatch(line);
if (dateMatch != null) {
// Save previous table if exists
if (currentTable != null && currentTable.isNotEmpty) {
tables.add(_TableData(currentHeader ?? '', currentTable, currentYear, currentMonth));
tables.add(
_TableData(
currentHeader ?? '',
currentTable,
currentYear,
currentMonth,
),
);
}
// Start new table
@ -105,7 +112,14 @@ class ContentDealService { @@ -105,7 +112,14 @@ class ContentDealService {
// Check for table end
if (line.contains('Delta T =') && currentTable != null) {
tables.add(_TableData(currentHeader ?? '', currentTable, currentYear, currentMonth));
tables.add(
_TableData(
currentHeader ?? '',
currentTable,
currentYear,
currentMonth,
),
);
currentTable = null;
continue;
}
@ -118,13 +132,25 @@ class ContentDealService { @@ -118,13 +132,25 @@ class ContentDealService {
// Add last table if exists
if (currentTable != null && currentTable.isNotEmpty) {
tables.add(_TableData(currentHeader ?? '', currentTable, currentYear, currentMonth));
tables.add(
_TableData(
currentHeader ?? '',
currentTable,
currentYear,
currentMonth,
),
);
}
return tables.where((table) => table.content.isNotEmpty).toList(); //
}
String _processTable(List<String> tableLines, int year, String month, {bool emitHeader = false}) {
String _processTable(
List<String> tableLines,
int year,
String month, {
bool emitHeader = false,
}) {
final buffer = StringBuffer();
bool foundHeader = false;
int weekDayIndex = 0;
@ -195,9 +221,13 @@ class ContentDealService { @@ -195,9 +221,13 @@ class ContentDealService {
var remainingLine = line.trim();
// 1. +
var firstCellMatch = RegExp(r'^([A-Za-z]\d{1,2})\b').firstMatch(remainingLine);
var firstCellMatch = RegExp(
r'^([A-Za-z]\d{1,2})\b',
).firstMatch(remainingLine);
if (firstCellMatch == null) {
firstCellMatch = RegExp(r'^([A-Za-z])\s*(\d{1,2})\b').firstMatch(remainingLine);
firstCellMatch = RegExp(
r'^([A-Za-z])\s*(\d{1,2})\b',
).firstMatch(remainingLine);
if (firstCellMatch != null) {
remainingLine = remainingLine.substring(firstCellMatch.end).trim();
}
@ -304,28 +334,26 @@ class ContentDealService { @@ -304,28 +334,26 @@ class ContentDealService {
//
final body = List.generate(tables.length, (index) {
final t = tables[index];
return _processTable(
t.content,
t.year,
t.month,
emitHeader: false,
);
return _processTable(t.content, t.year, t.month, emitHeader: false);
}).where((s) => s.isNotEmpty).join('\n');
return headerCsv != null && headerCsv.isNotEmpty ? '$headerCsv\n$body' : body;
return headerCsv != null && headerCsv.isNotEmpty
? '$headerCsv\n$body'
: body;
}
String _buildHeaderCsv(String line) {
var headerCells = line.trim().split(RegExp(r'\s+'));
headerCells = headerCells
.take(headerCells.length - 1) // Day
.map((cell) {
if (cell.length == 1 && _headerCharMap.containsKey(cell)) {
return _headerCharMap[cell]!;
}
return cell;
})
.toList();
headerCells =
headerCells
.take(headerCells.length - 1) // Day
.map((cell) {
if (cell.length == 1 && _headerCharMap.containsKey(cell)) {
return _headerCharMap[cell]!;
}
return cell;
})
.toList();
headerCells.insert(0, 'Weekday');
headerCells.insert(0, 'Date');
return headerCells.join(',');

305
win_text_editor/lib/modules/pdf_parse/services/excel_data_adjustment_service.dart

@ -1,311 +1,32 @@ @@ -1,311 +1,32 @@
import 'package:excel/excel.dart';
class ExcelDataAdjustmentService {
static const Map<String, int> palaceDegreeAdjustments = {
'': 300,
'': 270,
'': 240,
'': 210,
'': 180,
'': 150,
'': 120,
'': 90,
'': 60,
'': 30,
'': 0,
'': 330,
};
// 宿宿
static const List<Map<String, dynamic>> starConstellations = [
{'name': '', 'start': 34.342, 'end': 47.315}, // 34°20'32" -> 34.342°, 47°18'52" -> 47.315°
{'name': '', 'start': 47.315, 'end': 59.795}, // 47°18'52" -> 47.315°, 59°47'43" -> 59.795°
{'name': '', 'start': 59.795, 'end': 68.863}, // 59°47'43" -> 59.795°, 68°51'47" -> 68.863°
{'name': '', 'start': 68.863, 'end': 84.063}, // 68°51'47" -> 68.863°, 84°03'48" -> 84.063°
{'name': '', 'start': 84.063, 'end': 85.064}, // 84°03'48" -> 84.063°, 85°03'51" -> 85.064°
{'name': '', 'start': 85.064, 'end': 95.680}, // 85°03'51" -> 85.064°, 95°40'47" -> 95.680°
{'name': '', 'start': 95.680, 'end': 126.129}, // 95°40'47" -> 95.680°, 126°07'46" -> 126.129°
{'name': '', 'start': 126.129, 'end': 131.118}, // 126°07'46" -> 126.129°, 131°07'06" -> 131.118°
{'name': '', 'start': 131.118, 'end': 147.100}, // 131°07'06" -> 131.118°, 147°06'02" -> 147.100°
{'name': '', 'start': 147.100, 'end': 155.092}, // 147°06'02" -> 147.100°, 155°05'30" -> 155.092°
{'name': '', 'start': 155.092, 'end': 174.165}, // 155°05'30" -> 155.092°, 174°09'53" -> 174.165°
{'name': '', 'start': 174.165, 'end': 191.096}, // 174°09'53" -> 174.165°, 191°05'46" -> 191.096°
{'name': '', 'start': 191.096, 'end': 203.901}, // 191°05'46" -> 191.096°, 203°54'05" -> 203.901°
{'name': '', 'start': 203.901, 'end': 214.888}, // 203°54'05" -> 203.901°, 214°53'14" -> 214.888°
{'name': '', 'start': 214.888, 'end': 225.477}, // 214°53'14" -> 214.888°, 225°28'37" -> 225.477°
{'name': '', 'start': 225.477, 'end': 243.325}, // 225°28'37" -> 225.477°, 243°19'30" -> 243.325°
{'name': '', 'start': 243.325, 'end': 248.175}, // 243°19'30" -> 243.325°, 248°10'29" -> 248.175°
{'name': '', 'start': 248.175, 'end': 256.429}, // 248°10'29" -> 248.175°, 256°25'44" -> 256.429°
{'name': '', 'start': 256.429, 'end': 271.624}, // 256°25'44" -> 256.429°, 271°37'27" -> 271.624°
{'name': '', 'start': 271.624, 'end': 280.561}, // 271°37'27" -> 271.624°, 280°33'40" -> 280.561°
{'name': '', 'start': 280.561, 'end': 304.477}, // 280°33'40" -> 280.561°, 304°28'37" -> 304.477°
{'name': '', 'start': 304.477, 'end': 312.144}, // 304°28'37" -> 304.477°, 312°08'39" -> 312.144°
{'name': '', 'start': 312.144, 'end': 323.812}, // 312°08'39" -> 312.144°, 323°48'42" -> 323.812°
{'name': '', 'start': 323.812, 'end': 333.781}, // 323°48'42" -> 323.812°, 333°46'51" -> 333.781°
{'name': '', 'start': 333.781, 'end': 353.851}, // 333°46'51" -> 333.781°, 353°51'04" -> 353.851°
{'name': '', 'start': 353.851, 'end': 10.603}, // 353°51'04" -> 353.851°, 10°36'11" -> 10.603°
{'name': '', 'start': 10.603, 'end': 22.824}, // 10°36'11" -> 10.603°, 22°49'26" -> 22.824°
{'name': '', 'start': 22.824, 'end': 34.342}, // 22°49'26" -> 22.824°, 34°20'32" -> 34.342°
];
// 宿
String getStarConstellation(double degrees) {
// 0
for (final constellation in starConstellations) {
final start = constellation['start'] as double;
final end = constellation['end'] as double;
if (start <= end) {
// start < end
if (degrees >= start && degrees < end) {
return constellation['name'] as String;
}
} else {
// 0start > end353.851° -> 10.603°
if (degrees >= start || degrees < end) {
return constellation['name'] as String;
}
}
}
return ''; // 宿
}
//
double? _extractDegreesFromCell(String cellValue) {
if (cellValue.isEmpty) return null;
// R/D
String cleanedValue = cellValue.replaceAll(RegExp(r'[RD]'), '');
cleanedValue = cleanedValue.replaceAll(RegExp(r'[""]+'), ''); //
//
// 1: "15°30'45" "15°30"
var match = RegExp(r"^(\d+)\s*°\s*(\d+)\s*(?:['′]\s*(\d{1,2})\s*)?$").firstMatch(cleanedValue);
if (match != null) {
try {
final degrees = int.parse(match.group(1)!);
final minutes = int.parse(match.group(2)!);
final seconds = match.group(3) != null ? int.parse(match.group(3)!) : 0;
//
return degrees + (minutes / 60.0) + (seconds / 3600.0);
} catch (e) {
return null;
}
}
// 2: "15.5°" "15.5"
match = RegExp(r"^(\d+\.?\d*)\s*°?\s*$").firstMatch(cleanedValue);
if (match != null) {
try {
return double.parse(match.group(1)!);
} catch (e) {
return null;
}
}
// 3: "15" ()
match = RegExp(r"^(\d+)\s*$").firstMatch(cleanedValue);
if (match != null) {
try {
return double.parse(match.group(1)!);
} catch (e) {
return null;
}
}
//
print(' - 清理后值: "$cleanedValue" (无法匹配任何度数格式)');
return null;
}
//
String _getColumnTitle(int colIndex) {
const Map<int, String> columnTitles = {
4: '',
5: '',
6: '',
7: '',
8: '',
9: '',
10: '',
11: '',
12: '',
13: '',
14: '',
15: '',
16: '',
17: '',
};
return columnTitles[colIndex] ?? '未知';
}
static final _degreeFormatRegex = RegExp(
r"^(\d+)\s*([^\d\s°']+)\s*(\d+)\s*(?:['′]\s*(\d{1,2})\s*)?$",
caseSensitive: false,
);
//
// 宿
//
List<String?> processRowData(
List<String> cells,
Map<int, String> previousPalaces,
Sheet sheet,
int rowIndex,
int startCol, //
int startCol,
) {
List<String?> currentRowPalaces = List.filled(14, null);
int outputCol = startCol; // 使
//
int outputCol = startCol;
// 宿
bool isDebugRow = rowIndex < 5;
for (int col = 4; col <= 17 && col < cells.length; col++) {
final cellValue = cells[col];
// 1.
final palace = _extractPalace(cellValue);
String palaceToWrite = palace;
// R/D使
if (palaceToWrite.isEmpty || palaceToWrite == 'R' || palaceToWrite == 'D') {
palaceToWrite = previousPalaces[col] ?? '';
} else {
//
previousPalaces[col] = palaceToWrite;
}
// 2.
final displayValue = _getFormattedValueWithAdjustment(cellValue, palaceToWrite);
// 4
for (int col = 4; col < cells.length; col++) {
final cellValue = col < cells.length ? cells[col] : '';
// 3. 宿
String palaceWithConstellation = palaceToWrite;
String starConstellation = '';
double? adjustedDegrees = null;
if (palaceToWrite.isNotEmpty) {
//
adjustedDegrees = _extractDegreesFromCell(displayValue);
if (adjustedDegrees != null) {
starConstellation = getStarConstellation(adjustedDegrees);
if (starConstellation.isNotEmpty) {
palaceWithConstellation = '$palaceToWrite$starConstellation';
}
}
// 宿
if (isDebugRow) {
final columnTitle = _getColumnTitle(col);
final originalDegrees = _extractDegreesFromCell(cellValue);
if (adjustedDegrees != null) {
print('${rowIndex + 1}${columnTitle}: 原始坐标${originalDegrees?.toStringAsFixed(3) ?? "未知"}° -> 宫位:$palaceToWrite -> 修正后坐标${adjustedDegrees.toStringAsFixed(3)}° -> 星宿:$starConstellation -> 结果:$palaceWithConstellation');
} else {
print('${rowIndex + 1}${columnTitle}: 无法解析修正后坐标 -> 宫位:$palaceToWrite, 星宿:$starConstellation -> 结果:$palaceWithConstellation');
//
print(' - 原始值: "$cellValue"');
print(' - 修正后值: "$displayValue"');
print(' - 宫位: "$palaceToWrite"');
//
final originalDegrees = _extractDegreesFromCell(cellValue);
if (originalDegrees != null) {
print(' - 原始值可提取度数: ${originalDegrees.toStringAsFixed(3)}°');
} else {
print(' - 原始值无法提取度数');
}
}
}
}
currentRowPalaces[col - 4] = palaceWithConstellation;
// 4. 宿
//
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(palaceWithConstellation);
)).value = TextCellValue(cellValue);
outputCol++;
// 5.
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(displayValue);
outputCol++;
}
return currentRowPalaces;
}
String _getFormattedValueWithAdjustment(String originalValue, String palace) {
// 0. R/D
final rdMatches = RegExp(r'[RD]').allMatches(originalValue).map((m) => m.group(0)!).toList();
final rdFlags = rdMatches.join();
// 1. R/D
String normalized = originalValue.replaceAll('', "'").replaceAll(' ', '').replaceAll(' ', '');
String normalizedNoFlags = normalized.replaceAll(RegExp(r'[RD]'), '');
// 2.
String withDegreeSymbol = _replaceZodiacWithDegreeSymbol(normalizedNoFlags);
// 3.
String adjusted = withDegreeSymbol;
if (palace.isNotEmpty && palaceDegreeAdjustments.containsKey(palace)) {
adjusted = _adjustDegreeByPalace(withDegreeSymbol, palace);
}
// 4. R/D
String result = rdFlags.isNotEmpty ? '$adjusted$rdFlags' : adjusted;
//
result = result.replaceAll(RegExp(r'[""]+'), '"');
return result;
}
String _replaceZodiacWithDegreeSymbol(String value) {
//
if (value.contains('°')) {
return value; //
}
final match = _degreeFormatRegex.firstMatch(value);
if (match == null) return value;
final degreeStr = match.group(1);
final minuteStr = match.group(3);
final secondStr = match.group(4);
if (degreeStr == null || minuteStr == null) return value;
return '${degreeStr}°${minuteStr.padLeft(2, '0')}'
'${secondStr != null ? "'${secondStr.padLeft(2, '0')}\"" : ""}';
}
String _adjustDegreeByPalace(String valueWithDegree, String palace) {
final match = RegExp(r"^(\d+)°(\d+)(?:['](\d{1,2}))?").firstMatch(valueWithDegree);
if (match == null) return valueWithDegree;
final degreeStr = match.group(1);
final minuteStr = match.group(2);
final secondStr = match.group(3);
if (degreeStr == null || minuteStr == null) return valueWithDegree;
final originalDegree = int.tryParse(degreeStr) ?? 0;
final adjustment = palaceDegreeAdjustments[palace] ?? 0;
var adjustedDegree = originalDegree + adjustment;
adjustedDegree %= 360;
if (adjustedDegree < 0) adjustedDegree += 360;
return '${adjustedDegree}°${minuteStr.padLeft(2, '0')}'
'${secondStr != null ? "'${secondStr.padLeft(2, '0')}\"" : ""}';
}
String _extractPalace(String cellValue) {
final match = RegExp(r"[^\d\s°\'RDL]").firstMatch(cellValue.trim());
return match?.group(0) ?? '';
//
return List.filled(14, null);
}
}

434
win_text_editor/lib/modules/pdf_parse/services/excel_data_adjustment_service_backup.dart

@ -0,0 +1,434 @@ @@ -0,0 +1,434 @@
import 'package:excel/excel.dart';
class ExcelDataAdjustmentService {
static const Map<String, int> palaceDegreeAdjustments = {
'': 300,
'': 270,
'': 240,
'': 210,
'': 180,
'': 150,
'': 120,
'': 90,
'': 60,
'': 30,
'': 0,
'': 330,
};
// 宿宿
static const List<Map<String, dynamic>> starConstellations = [
{'name': '', 'start': 34.342, 'end': 47.315}, // 34°20'32" -> 34.342°, 47°18'52" -> 47.315°
{'name': '', 'start': 47.315, 'end': 59.795}, // 47°18'52" -> 47.315°, 59°47'43" -> 59.795°
{'name': '', 'start': 59.795, 'end': 68.863}, // 59°47'43" -> 59.795°, 68°51'47" -> 68.863°
{'name': '', 'start': 68.863, 'end': 84.063}, // 68°51'47" -> 68.863°, 84°03'48" -> 84.063°
{'name': '', 'start': 84.063, 'end': 85.064}, // 84°03'48" -> 84.063°, 85°03'51" -> 85.064°
{'name': '', 'start': 85.064, 'end': 95.680}, // 85°03'51" -> 85.064°, 95°40'47" -> 95.680°
{'name': '', 'start': 95.680, 'end': 126.129}, // 95°40'47" -> 95.680°, 126°07'46" -> 126.129°
{'name': '', 'start': 126.129, 'end': 131.118}, // 126°07'46" -> 126.129°, 131°07'06" -> 131.118°
{'name': '', 'start': 131.118, 'end': 147.100}, // 131°07'06" -> 131.118°, 147°06'02" -> 147.100°
{'name': '', 'start': 147.100, 'end': 155.092}, // 147°06'02" -> 147.100°, 155°05'30" -> 155.092°
{'name': '', 'start': 155.092, 'end': 174.165}, // 155°05'30" -> 155.092°, 174°09'53" -> 174.165°
{'name': '', 'start': 174.165, 'end': 191.096}, // 174°09'53" -> 174.165°, 191°05'46" -> 191.096°
{'name': '', 'start': 191.096, 'end': 203.901}, // 191°05'46" -> 191.096°, 203°54'05" -> 203.901°
{'name': '', 'start': 203.901, 'end': 214.888}, // 203°54'05" -> 203.901°, 214°53'14" -> 214.888°
{'name': '', 'start': 214.888, 'end': 225.477}, // 214°53'14" -> 214.888°, 225°28'37" -> 225.477°
{'name': '', 'start': 225.477, 'end': 243.325}, // 225°28'37" -> 225.477°, 243°19'30" -> 243.325°
{'name': '', 'start': 243.325, 'end': 248.175}, // 243°19'30" -> 243.325°, 248°10'29" -> 248.175°
{'name': '', 'start': 248.175, 'end': 256.429}, // 248°10'29" -> 248.175°, 256°25'44" -> 256.429°
{'name': '', 'start': 256.429, 'end': 271.624}, // 256°25'44" -> 256.429°, 271°37'27" -> 271.624°
{'name': '', 'start': 271.624, 'end': 280.561}, // 271°37'27" -> 271.624°, 280°33'40" -> 280.561°
{'name': '', 'start': 280.561, 'end': 304.477}, // 280°33'40" -> 280.561°, 304°28'37" -> 304.477°
{'name': '', 'start': 304.477, 'end': 312.144}, // 304°28'37" -> 304.477°, 312°08'39" -> 312.144°
{'name': '', 'start': 312.144, 'end': 323.812}, // 312°08'39" -> 312.144°, 323°48'42" -> 323.812°
{'name': '', 'start': 323.812, 'end': 333.781}, // 323°48'42" -> 323.812°, 333°46'51" -> 333.781°
{'name': '', 'start': 333.781, 'end': 353.851}, // 333°46'51" -> 333.781°, 353°51'04" -> 353.851°
{'name': '', 'start': 353.851, 'end': 10.603}, // 353°51'04" -> 353.851°, 10°36'11" -> 10.603°
{'name': '', 'start': 10.603, 'end': 22.824}, // 10°36'11" -> 10.603°, 22°49'26" -> 22.824°
{'name': '', 'start': 22.824, 'end': 34.342}, // 22°49'26" -> 22.824°, 34°20'32" -> 34.342°
];
// 宿
String getStarConstellation(double degrees) {
// 0
for (final constellation in starConstellations) {
final start = constellation['start'] as double;
final end = constellation['end'] as double;
if (start <= end) {
// start < end
if (degrees >= start && degrees < end) {
return constellation['name'] as String;
}
} else {
// 0start > end353.851° -> 10.603°
if (degrees >= start || degrees < end) {
return constellation['name'] as String;
}
}
}
return ''; // 宿
}
//
double? _extractDegreesFromCell(String cellValue) {
if (cellValue.isEmpty) return null;
// R/D
String cleanedValue = cellValue.replaceAll(RegExp(r'[RD]'), '');
cleanedValue = cleanedValue.replaceAll(RegExp(r'[""]+'), ''); //
//
// 1: "15°30'45" "15°30"
var match = RegExp(r"^(\d+)\s*°\s*(\d+)\s*(?:['′]\s*(\d{1,2})\s*)?$").firstMatch(cleanedValue);
if (match != null) {
try {
final degrees = int.parse(match.group(1)!);
final minutes = int.parse(match.group(2)!);
final seconds = match.group(3) != null ? int.parse(match.group(3)!) : 0;
//
return degrees + (minutes / 60.0) + (seconds / 3600.0);
} catch (e) {
return null;
}
}
// 2: "15.5°" "15.5"
match = RegExp(r"^(\d+\.?\d*)\s*°?\s*$").firstMatch(cleanedValue);
if (match != null) {
try {
return double.parse(match.group(1)!);
} catch (e) {
return null;
}
}
// 3: "15" ()
match = RegExp(r"^(\d+)\s*$").firstMatch(cleanedValue);
if (match != null) {
try {
return double.parse(match.group(1)!);
} catch (e) {
return null;
}
}
//
print(' - 清理后值: "$cleanedValue" (无法匹配任何度数格式)');
return null;
}
//
String _getColumnTitle(int colIndex) {
const Map<int, String> columnTitles = {
4: '',
5: '',
6: '', //
7: '',
8: '',
9: '',
10: '',
11: '',
12: '',
13: '',
14: '',
15: '',
16: '',
17: '',
18: '',
};
return columnTitles[colIndex] ?? '未知';
}
static final _degreeFormatRegex = RegExp(
r"^(\d+)\s*([^\d\s°']+)\s*(\d+)\s*(?:['′]\s*(\d{1,2})\s*)?$",
caseSensitive: false,
);
//
List<String?> processRowData(
List<String> cells,
Map<int, String> previousPalaces,
Sheet sheet,
int rowIndex,
int startCol, //
) {
List<String?> currentRowPalaces = List.filled(15, null); // 15
int outputCol = startCol; // 使
// 宿
bool isDebugRow = rowIndex < 5;
// 1-2
for (int i = 0; i < 2; i++) {
final col = 4 + i; // 4=, 5=
final cellValue = col < cells.length ? cells[col] : '';
// 1.
final palace = _extractPalace(cellValue);
String palaceToWrite = palace;
// R/D使
if (palaceToWrite.isEmpty || palaceToWrite == 'R' || palaceToWrite == 'D') {
palaceToWrite = previousPalaces[col] ?? '';
} else {
//
previousPalaces[col] = palaceToWrite;
}
// 2.
final displayValue = _getFormattedValueWithAdjustment(cellValue, palaceToWrite);
// 3. 宿
String palaceWithConstellation = palaceToWrite;
String starConstellation = '';
double? adjustedDegrees = null;
if (palaceToWrite.isNotEmpty) {
//
adjustedDegrees = _extractDegreesFromCell(displayValue);
if (adjustedDegrees != null) {
starConstellation = getStarConstellation(adjustedDegrees);
if (starConstellation.isNotEmpty) {
palaceWithConstellation = '$palaceToWrite$starConstellation';
}
}
//
if (isDebugRow) {
final columnTitle = _getColumnTitle(col);
final originalDegrees = _extractDegreesFromCell(cellValue);
if (adjustedDegrees != null) {
print('${rowIndex + 1}${columnTitle}: 原始坐标${originalDegrees?.toStringAsFixed(3) ?? "未知"}° -> 宫位:$palaceToWrite -> 修正后坐标${adjustedDegrees.toStringAsFixed(3)}° -> 星宿:$starConstellation -> 结果:$palaceWithConstellation');
} else {
print('${rowIndex + 1}${columnTitle}: 无法解析修正后坐标 -> 宫位:$palaceToWrite, 星宿:$starConstellation -> 结果:$palaceWithConstellation');
print(' - 原始值: "$cellValue"');
print(' - 修正后值: "$displayValue"');
print(' - 宫位: "$palaceToWrite"');
}
}
}
currentRowPalaces[i] = palaceWithConstellation;
// 4. 宿
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(palaceWithConstellation);
outputCol++;
// 5.
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(displayValue);
outputCol++;
}
// 3
// extendedCells中获取紫星数据
final purpleCellValue = cells.length > 6 ? cells[6] : '';
final purplePalace = _extractPalace(purpleCellValue);
String purplePalaceToWrite = purplePalace;
// R/D使
if (purplePalaceToWrite.isEmpty || purplePalaceToWrite == 'R' || purplePalaceToWrite == 'D') {
purplePalaceToWrite = previousPalaces[6] ?? '';
} else {
//
previousPalaces[6] = purplePalaceToWrite;
}
//
final purpleDisplayValue = _getFormattedValueWithAdjustment(purpleCellValue, purplePalaceToWrite);
// 宿
String purplePalaceWithConstellation = purplePalaceToWrite;
String purpleStarConstellation = '';
double? purpleAdjustedDegrees = null;
if (purplePalaceToWrite.isNotEmpty) {
//
purpleAdjustedDegrees = _extractDegreesFromCell(purpleDisplayValue);
if (purpleAdjustedDegrees != null) {
purpleStarConstellation = getStarConstellation(purpleAdjustedDegrees);
if (purpleStarConstellation.isNotEmpty) {
purplePalaceWithConstellation = '$purplePalaceToWrite$purpleStarConstellation';
}
}
//
if (isDebugRow) {
final originalDegrees = _extractDegreesFromCell(purpleCellValue);
if (purpleAdjustedDegrees != null) {
print('${rowIndex + 1}行 紫: 原始坐标${originalDegrees?.toStringAsFixed(3) ?? "未知"}° -> 宫位:$purplePalaceToWrite -> 修正后坐标${purpleAdjustedDegrees.toStringAsFixed(3)}° -> 星宿:$purpleStarConstellation -> 结果:$purplePalaceWithConstellation');
} else {
print('${rowIndex + 1}行 紫: 无法解析修正后坐标 -> 宫位:$purplePalaceToWrite, 星宿:$purpleStarConstellation -> 结果:$purplePalaceWithConstellation');
print(' - 原始值: "$purpleCellValue"');
print(' - 修正后值: "$purpleDisplayValue"');
print(' - 宫位: "$purplePalaceToWrite"');
}
}
}
currentRowPalaces[2] = purplePalaceWithConstellation;
// +宿
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(purplePalaceWithConstellation);
outputCol++;
//
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(purpleDisplayValue);
outputCol++;
// 4414
for (int i = 3; i < 15; i++) {
final col = 4 + i; // 6=, 7=, 8=, 9=, 10=, 11=, 12=, 13=, 14=, 15=, 16=, 17=
final cellValue = col < cells.length ? cells[col] : '';
// 1.
final palace = _extractPalace(cellValue);
String palaceToWrite = palace;
// R/D使
if (palaceToWrite.isEmpty || palaceToWrite == 'R' || palaceToWrite == 'D') {
palaceToWrite = previousPalaces[col] ?? '';
} else {
//
previousPalaces[col] = palaceToWrite;
}
// 2.
final displayValue = _getFormattedValueWithAdjustment(cellValue, palaceToWrite);
// 3. 宿
String palaceWithConstellation = palaceToWrite;
String starConstellation = '';
double? adjustedDegrees = null;
if (palaceToWrite.isNotEmpty) {
//
adjustedDegrees = _extractDegreesFromCell(displayValue);
if (adjustedDegrees != null) {
starConstellation = getStarConstellation(adjustedDegrees);
if (starConstellation.isNotEmpty) {
palaceWithConstellation = '$palaceToWrite$starConstellation';
}
}
//
if (isDebugRow) {
final columnTitle = _getColumnTitle(col);
final originalDegrees = _extractDegreesFromCell(cellValue);
if (adjustedDegrees != null) {
print('${rowIndex + 1}${columnTitle}: 原始坐标${originalDegrees?.toStringAsFixed(3) ?? "未知"}° -> 宫位:$palaceToWrite -> 修正后坐标${adjustedDegrees.toStringAsFixed(3)}° -> 星宿:$starConstellation -> 结果:$palaceWithConstellation');
} else {
print('${rowIndex + 1}${columnTitle}: 无法解析修正后坐标 -> 宫位:$palaceToWrite, 星宿:$starConstellation -> 结果:$palaceWithConstellation');
print(' - 原始值: "$cellValue"');
print(' - 修正后值: "$displayValue"');
print(' - 宫位: "$palaceToWrite"');
}
}
}
currentRowPalaces[i] = palaceWithConstellation;
// 4. 宿
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(palaceWithConstellation);
outputCol++;
// 5.
sheet.cell(CellIndex.indexByColumnRow(
columnIndex: outputCol,
rowIndex: rowIndex
)).value = TextCellValue(displayValue);
outputCol++;
}
return currentRowPalaces;
}
String _getFormattedValueWithAdjustment(String originalValue, String palace) {
// 0. R/D
final rdMatches = RegExp(r'[RD]').allMatches(originalValue).map((m) => m.group(0)!).toList();
final rdFlags = rdMatches.join();
// 1. R/D
String normalized = originalValue.replaceAll('', "'").replaceAll(' ', '').replaceAll(' ', '');
String normalizedNoFlags = normalized.replaceAll(RegExp(r'[RD]'), '');
// 2.
String withDegreeSymbol = _replaceZodiacWithDegreeSymbol(normalizedNoFlags);
// 3.
String adjusted = withDegreeSymbol;
if (palace.isNotEmpty && palaceDegreeAdjustments.containsKey(palace)) {
adjusted = _adjustDegreeByPalace(withDegreeSymbol, palace);
}
// 4. R/D
String result = rdFlags.isNotEmpty ? '$adjusted$rdFlags' : adjusted;
//
result = result.replaceAll(RegExp(r'[""]+'), '"');
return result;
}
String _replaceZodiacWithDegreeSymbol(String value) {
//
if (value.contains('°')) {
return value; //
}
final match = _degreeFormatRegex.firstMatch(value);
if (match == null) return value;
final degreeStr = match.group(1);
final minuteStr = match.group(3);
final secondStr = match.group(4);
if (degreeStr == null || minuteStr == null) return value;
return '${degreeStr}°${minuteStr.padLeft(2, '0')}'
'${secondStr != null ? "'${secondStr.padLeft(2, '0')}\"" : ""}';
}
String _adjustDegreeByPalace(String valueWithDegree, String palace) {
final match = RegExp(r"^(\d+)°(\d+)(?:['](\d{1,2}))?").firstMatch(valueWithDegree);
if (match == null) return valueWithDegree;
final degreeStr = match.group(1);
final minuteStr = match.group(2);
final secondStr = match.group(3);
if (degreeStr == null || minuteStr == null) return valueWithDegree;
final originalDegree = int.tryParse(degreeStr) ?? 0;
final adjustment = palaceDegreeAdjustments[palace] ?? 0;
var adjustedDegree = originalDegree + adjustment;
adjustedDegree %= 360;
if (adjustedDegree < 0) adjustedDegree += 360;
return '${adjustedDegree}°${minuteStr.padLeft(2, '0')}'
'${secondStr != null ? "'${secondStr.padLeft(2, '0')}\"" : ""}';
}
String _extractPalace(String cellValue) {
final match = RegExp(r"[^\d\s°\'RDL]").firstMatch(cellValue.trim());
return match?.group(0) ?? '';
}
}

32
win_text_editor/lib/modules/pdf_parse/services/excel_deal_service.dart

@ -13,18 +13,19 @@ class ExcelDealService { @@ -13,18 +13,19 @@ class ExcelDealService {
static const Map<int, String> _columnTitles = {
4: '',
5: '',
6: '',
7: '',
8: '',
9: '',
10: '',
11: '',
12: '',
13: '',
14: '',
15: '',
16: '',
17: '',
6: '', //
7: '',
8: '',
9: '',
10: '',
11: '',
12: '',
13: '',
14: '',
15: '',
16: '',
17: '',
18: '',
};
Future<void> exportToExcel(String processedContent, {String? fileName}) async {
@ -88,14 +89,14 @@ class ExcelDealService { @@ -88,14 +89,14 @@ class ExcelDealService {
}
// 2. 5-18
for (int col = 4; col <= 17 && col < cells.length; col++) {
for (int col = 4; col <= 18 && col < cells.length; col++) {
final title = _columnTitles[col] ?? '';
extendedCells.add('${title}'); // 宿
extendedCells.add(cells[col]);
}
// 3.
extendedCells.addAll(['', '', '']);
extendedCells.addAll(['', '', '', '', '半合']);
//
for (int col = 0; col < extendedCells.length; col++) {
@ -112,7 +113,8 @@ class ExcelDealService { @@ -112,7 +113,8 @@ class ExcelDealService {
void _setColumnWidths(Sheet sheet) {
// + +宿 +
// 2+宿
for (var i = 0; i < 4 + (_columnTitles.length * 2) + 3; i++) {
// 4 + 15宿×2 + 5 = 4 + 30 + 5 = 39
for (var i = 0; i < 4 + (15 * 2) + 5; i++) {
sheet.setColumnWidth(i, 8.0);
}
}

21
win_text_editor/lib/modules/pdf_parse/services/relationship_calculator_service.dart

@ -7,6 +7,8 @@ class RelationshipCalculatorService { @@ -7,6 +7,8 @@ class RelationshipCalculatorService {
static const List<String> zodiacColumns = [
'', //
'',
'', //
'',
'',
'',
@ -195,9 +197,9 @@ class RelationshipCalculatorService { @@ -195,9 +197,9 @@ class RelationshipCalculatorService {
continue; //
}
// Check for conjunction (0°±30 minutes 120°±30 minutes)
if (circularDiff <= 30 || (circularDiff >= 7170 && circularDiff <= 7290)) {
// 0°00' to 0°30' 119°30' to 120°29'
// Check for conjunction (0°±30 minutes)
if (circularDiff <= 30) {
// 0°00' to 0°30'
conjunctions.add('${planets[i]}${planets[j]}');
}
// Check for square (90°±30 minutes)
@ -211,15 +213,20 @@ class RelationshipCalculatorService { @@ -211,15 +213,20 @@ class RelationshipCalculatorService {
// 179°30' to 180°29'
oppositions.add('${planets[i]}${planets[j]}');
}
//
else if (degI == degJ) {
huis.add('${planets[i]}${planets[j]}');
}
// 60°±3059°30'到60°29'
// 59°30' = 3570分钟,60°29' = 3629
else if (circularDiff >= 3570 && circularDiff <= 3629) {
banhes.add('${planets[i]}${planets[j]}半合');
}
// 120°±30119°30'到120°29'
// 119°30' = 7170分钟,120°29' = 7229
else if (circularDiff >= 7170 && circularDiff <= 7229) {
banhes.add('${planets[i]}${planets[j]}半合');
}
//
else if (degI == degJ) {
huis.add('${planets[i]}${planets[j]}');
}
}
}

91
win_text_editor/lib/modules/pdf_parse/widgets/pdf_parse_output.dart

@ -11,7 +11,11 @@ class PdfParseOutput extends StatefulWidget { @@ -11,7 +11,11 @@ class PdfParseOutput extends StatefulWidget {
final PdfParseController controller;
final TextEditingController codeController;
const PdfParseOutput({super.key, required this.controller, required this.codeController});
const PdfParseOutput({
super.key,
required this.controller,
required this.codeController,
});
@override
State<PdfParseOutput> createState() => _PdfParseOutputState();
@ -46,7 +50,8 @@ class _PdfParseOutputState extends State<PdfParseOutput> { @@ -46,7 +50,8 @@ class _PdfParseOutputState extends State<PdfParseOutput> {
void _computeDisplay() {
if (_selectedOperation != null) {
//
if (widget.controller.filePath.isEmpty || widget.controller.contentSections.isEmpty) {
if (widget.controller.filePath.isEmpty ||
widget.controller.contentSections.isEmpty) {
widget.codeController.text = '';
_csvRows = [];
return;
@ -57,7 +62,8 @@ class _PdfParseOutputState extends State<PdfParseOutput> { @@ -57,7 +62,8 @@ class _PdfParseOutputState extends State<PdfParseOutput> {
widget.codeController.text = fullProcessed; //
_csvRows = _parseCsv(fullProcessed);
} else {
widget.codeController.text = widget.controller.genContentString([_selectedOperation!]) ?? '';
widget.codeController.text =
widget.controller.genContentString([_selectedOperation!]) ?? '';
_csvRows = [];
}
} else {
@ -78,9 +84,12 @@ class _PdfParseOutputState extends State<PdfParseOutput> { @@ -78,9 +84,12 @@ class _PdfParseOutputState extends State<PdfParseOutput> {
final headers = _csvRows.first;
final data = _csvRows.sublist(1);
final columns = headers
.map<GridColumn>((h) => MyGridColumn(columnName: h, label: h, minimumWidth: 120))
.toList();
final columns =
headers
.map<GridColumn>(
(h) => MyGridColumn(columnName: h, label: h, minimumWidth: 120),
)
.toList();
final source = _SimpleCsvDataSource(headers: headers, rows: data);
@ -155,24 +164,26 @@ class _PdfParseOutputState extends State<PdfParseOutput> { @@ -155,24 +164,26 @@ class _PdfParseOutputState extends State<PdfParseOutput> {
Widget _buildAnalyzedGrid() {
final data = widget.controller.analyzedTable;
if (data.isEmpty) {
return Center(
child: ElevatedButton(
onPressed: () {
widget.controller.generateAnalyzedTable();
},
child: const Text('点击生成数据分析结果'),
),
);
//
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.controller.generateAnalyzedTable();
});
return const Center(child: CircularProgressIndicator());
}
final headers = data.first;
// 180
final rows =
data.length > 181 ? data.sublist(1, 1 + 180) : data.sublist(1);
final columns = headers
.map<GridColumn>((h) => MyGridColumn(columnName: h, label: h, minimumWidth: 100))
.toList();
final source = _SimpleCsvDataSource(headers: headers.cast<String>(), rows: rows.cast<List<String>>());
// 400
final rows = data.length > 401 ? data.sublist(1, 1 + 400) : data.sublist(1);
final columns =
headers
.map<GridColumn>(
(h) => MyGridColumn(columnName: h, label: h, minimumWidth: 100),
)
.toList();
final source = _SimpleCsvDataSource(
headers: headers.cast<String>(),
rows: rows.cast<List<String>>(),
);
return Container(
color: Colors.white,
@ -200,32 +211,38 @@ class _SimpleCsvDataSource extends DataGridSource { @@ -200,32 +211,38 @@ class _SimpleCsvDataSource extends DataGridSource {
final List<String> headers;
final List<List<String>> _rows;
_SimpleCsvDataSource({required this.headers, required List<List<String>> rows}) : _rows = rows;
_SimpleCsvDataSource({
required this.headers,
required List<List<String>> rows,
}) : _rows = rows;
@override
List<DataGridRow> get rows =>
_rows
.map((r) => DataGridRow(
cells: List.generate(
headers.length,
(i) => DataGridCell<String>(
columnName: headers[i],
value: i < r.length ? r[i] : '',
),
.map(
(r) => DataGridRow(
cells: List.generate(
headers.length,
(i) => DataGridCell<String>(
columnName: headers[i],
value: i < r.length ? r[i] : '',
),
))
),
),
)
.toList();
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells: row.getCells().map((c) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
alignment: Alignment.centerLeft,
child: Text(c.value?.toString() ?? ''),
);
}).toList(),
cells:
row.getCells().map((c) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
alignment: Alignment.centerLeft,
child: Text(c.value?.toString() ?? ''),
);
}).toList(),
);
}
}

Loading…
Cancel
Save