diff --git a/internal/ui/practice_session.go b/internal/ui/practice_session.go index 3701fc2..91115ef 100644 --- a/internal/ui/practice_session.go +++ b/internal/ui/practice_session.go @@ -341,7 +341,7 @@ func (m *PracticeSession) handleAnswerSubmission() (tea.Model, tea.Cmd) { originalItem := m.getCurrentRawItem() expectedInput := m.getExpectedInput(originalItem) - isCorrect := m.isInputCorrect(userInput, expectedInput) + isCorrect := m.isInputCorrectForItem(userInput, originalItem) m.recordSpacedRepetition(originalItem, isCorrect) if isCorrect { @@ -972,6 +972,55 @@ func (m PracticeSession) getExpectedInput(item string) string { return item } +func (m PracticeSession) isInputCorrectForItem(userInput, item string) bool { + acceptedInputs := m.getAcceptedInputs(item) + for _, expected := range acceptedInputs { + if expected == "" { + continue + } + if m.isInputCorrect(userInput, expected) { + return true + } + } + return false +} + +func (m PracticeSession) getAcceptedInputs(item string) []string { + expected := strings.TrimSpace(m.getExpectedInput(item)) + trimmedItem := strings.TrimSpace(item) + _, translation := practice.ParseLine(item) + translation = strings.TrimSpace(translation) + + acceptedSet := make(map[string]struct{}) + if expected != "" { + acceptedSet[expected] = struct{}{} + } + if trimmedItem != "" { + acceptedSet[trimmedItem] = struct{}{} + } + + if expected != "" && translation != "" { + withSpace := strings.TrimSpace(expected + " " + translation) + if withSpace != "" { + acceptedSet[withSpace] = struct{}{} + } + withArrow := strings.TrimSpace(expected + " ->> " + translation) + if withArrow != "" { + acceptedSet[withArrow] = struct{}{} + } + } + + if len(acceptedSet) == 0 && trimmedItem != "" { + return []string{trimmedItem} + } + + result := make([]string, 0, len(acceptedSet)) + for candidate := range acceptedSet { + result = append(result, candidate) + } + return result +} + // 检查输入是否正确 func (m PracticeSession) isInputCorrect(userInput, expectedInput string) bool { // 获取匹配模式 diff --git a/internal/ui/practice_session_test.go b/internal/ui/practice_session_test.go index 7574f9b..4c28541 100644 --- a/internal/ui/practice_session_test.go +++ b/internal/ui/practice_session_test.go @@ -192,6 +192,75 @@ func TestIsInputCorrect(t *testing.T) { } } +func TestIsInputCorrectForItem(t *testing.T) { + setupPracticeSessionTest(t) + + session := &PracticeSession{} + item := "People often use the phrase '2' in conversation. ->> In everyday conversations, people frequently mention 'a great number of' when they want to emphasize quantity." + + config.AppConfig.CorrectnessMatchMode = "exact_match" + exactMatchCases := []struct { + name string + input string + want bool + }{ + { + name: "只输入原文", + input: "People often use the phrase '2' in conversation.", + want: true, + }, + { + name: "输入原文和翻译", + input: "People often use the phrase '2' in conversation. In everyday conversations, people frequently mention 'a great number of' when they want to emphasize quantity.", + want: true, + }, + { + name: "输入带箭头的完整原始行", + input: "People often use the phrase '2' in conversation. ->> In everyday conversations, people frequently mention 'a great number of' when they want to emphasize quantity.", + want: true, + }, + { + name: "仅输入翻译", + input: "In everyday conversations, people frequently mention 'a great number of' when they want to emphasize quantity.", + want: false, + }, + } + + for _, tt := range exactMatchCases { + t.Run(tt.name, func(t *testing.T) { + if got := session.isInputCorrectForItem(tt.input, item); got != tt.want { + t.Errorf("isInputCorrectForItem() = %v, want %v", got, tt.want) + } + }) + } + + config.AppConfig.CorrectnessMatchMode = "word_match" + wordMatchCases := []struct { + name string + input string + want bool + }{ + { + name: "忽略标点仍判定正确", + input: "People often use the phrase 2 in conversation In everyday conversations people frequently mention a great number of when they want to emphasize quantity", + want: true, + }, + { + name: "单词错误仍判定错误", + input: "People often use the phrase two in chat. In common talks, folks often mention a great number when they want to emphasize quantity.", + want: false, + }, + } + + for _, tt := range wordMatchCases { + t.Run(tt.name, func(t *testing.T) { + if got := session.isInputCorrectForItem(tt.input, item); got != tt.want { + t.Errorf("isInputCorrectForItem() = %v, want %v", got, tt.want) + } + }) + } +} + // 测试normalizeForWordMatch方法 func TestNormalizeForWordMatch(t *testing.T) { // 创建测试会话 @@ -245,9 +314,9 @@ func TestGetCurrentItem(t *testing.T) { // 创建测试会话 session := &PracticeSession{ - resourceType: practice.Words, - items: []string{"apple ->> 苹果", "banana ->> 香蕉", "orange ->> 橙子"}, - practiceOrder: []int{0, 1, 2}, + resourceType: practice.Words, + items: []string{"apple ->> 苹果", "banana ->> 香蕉", "orange ->> 橙子"}, + practiceOrder: []int{0, 1, 2}, completedCount: 0, } @@ -357,4 +426,4 @@ func TestGetCurrentItem(t *testing.T) { if result != "" { t.Errorf("超出范围 getCurrentItem() = %v, want empty string", result) } -} \ No newline at end of file +} diff --git a/mllt-cli b/mllt-cli index 4398fce..ae3f930 100755 Binary files a/mllt-cli and b/mllt-cli differ