-
-
Notifications
You must be signed in to change notification settings - Fork 362
feat(IPinyinService): add IPinyinService interface #6968
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Reviewer's GuideThis PR adds a new IPinyinService interface and associated enum, provides a DefaultPinyinService implementation with caching and CartesianProduct logic, registers the service in DI, and includes unit tests to validate its methods. Class diagram for new Pinyin service typesclassDiagram
class IPinyinService {
+HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory)
+HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory)
+bool IsChinese(char c)
+bool ContainsChinese(string text)
}
class DefaultPinyinService {
+HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory)
+HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory)
+bool IsChinese(char c)
+bool ContainsChinese(string text)
-static Dictionary<string, string> Cache
-static HashSet<string> CartesianProduct<T>(List<List<T>> sequences, PinyinLetterCaseCategory caseCategory, string separator)
}
class PinyinLetterCaseCategory {
<<enumeration>>
UppercaseLetter
LowercaseLetter
}
DefaultPinyinService --|> IPinyinService
IPinyinService ..> PinyinLetterCaseCategory
DefaultPinyinService ..> PinyinLetterCaseCategory
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/BootstrapBlazor/Services/Pinyin/DefaultPinyinService.cs:10` </location>
<code_context>
+
+sealed class DefaultPinyinService : IPinyinService
+{
+ public HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter)
+ {
+ var letters = new List<List<char>>();
</code_context>
<issue_to_address>
**suggestion:** GetFirstLetters does not filter non-Chinese characters.
Non-Chinese characters may lead to empty segments and impact the Cartesian product logic. Please filter or handle them to ensure correct output.
Suggested implementation:
```csharp
foreach (var c in text)
{
// Filter non-Chinese characters
if (IsChineseCharacter(c))
{
var segment = new List<char>();
foreach (var item in Cache.Where(item => item.Value.Contains(c, StringComparison.InvariantCulture)))
{
var l = item.Key.First();
segment.Add(l);
}
// Only add non-empty segments
if (segment.Count > 0)
{
letters.Add(segment);
}
}
}
```
```csharp
// Helper method to check if a character is Chinese
private static bool IsChineseCharacter(char c)
{
// CJK Unified Ideographs: U+4E00 to U+9FFF
return c >= 0x4E00 && c <= 0x9FFF;
}
```
If `IsChineseCharacter` should be placed elsewhere (e.g., in a utility class), please move it accordingly. Also, ensure that the rest of the method logic (such as the Cartesian product) works with the filtered `letters` list.
</issue_to_address>
### Comment 2
<location> `src/BootstrapBlazor/Services/Pinyin/DefaultPinyinService.cs:27` </location>
<code_context>
+ return CartesianProduct(letters, caseCategory);
+ }
+
+ public HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory)
+ {
+ var letters = new List<List<string>>();
</code_context>
<issue_to_address>
**issue:** GetPinyin omits a default value for caseCategory.
The implementation requires callers to specify caseCategory, which may cause inconsistencies with the interface. Please update the method signature to include a default value for caseCategory.
</issue_to_address>
### Comment 3
<location> `src/BootstrapBlazor/Services/Pinyin/DefaultPinyinService.cs:57` </location>
<code_context>
+ : string.Join(separator, i))];
+ }
+
+ public bool IsChinese(char c) => c >= 0x4E00 && c <= 0x9FA5;
+
+ public bool ContainsChinese(string text) => text.Any(IsChinese);
</code_context>
<issue_to_address>
**suggestion:** IsChinese only covers a subset of Chinese characters.
The current range excludes characters from Extension blocks. For broader coverage, expand the range or use a more comprehensive Unicode check.
```suggestion
public bool IsChinese(char c)
{
// CJK Unified Ideographs
if (c >= 0x4E00 && c <= 0x9FFF) return true;
// CJK Unified Ideographs Extension A
if (c >= 0x3400 && c <= 0x4DBF) return true;
// CJK Unified Ideographs Extension B
if (c >= 0x20000 && c <= 0x2A6DF) return true;
// CJK Unified Ideographs Extension C
if (c >= 0x2A700 && c <= 0x2B73F) return true;
// CJK Unified Ideographs Extension D
if (c >= 0x2B740 && c <= 0x2B81F) return true;
// CJK Unified Ideographs Extension E
if (c >= 0x2B820 && c <= 0x2CEAF) return true;
// CJK Unified Ideographs Extension F
if (c >= 0x2CEB0 && c <= 0x2EBEF) return true;
// CJK Unified Ideographs Extension G
if (c >= 0x30000 && c <= 0x3134F) return true;
return false;
}
```
</issue_to_address>
### Comment 4
<location> `test/UnitTest/Services/PinyinServiceTest.cs:10-11` </location>
<code_context>
+
+public class PinyinServiceTest : BootstrapBlazorTestBase
+{
+ [Fact]
+ public async Task GetFirstLetters_Ok()
+ {
+ var service = Context.Services.GetRequiredService<IPinyinService>();
</code_context>
<issue_to_address>
**suggestion (testing):** Missing edge case tests for empty and non-Chinese input in GetFirstLetters.
Add tests for empty string and non-Chinese character inputs to verify correct handling of these edge cases.
</issue_to_address>
### Comment 5
<location> `src/BootstrapBlazor/Services/Pinyin/DefaultPinyinService.cs:16` </location>
<code_context>
+ foreach (var c in text)
+ {
+ var segment = new List<char>();
+ foreach (var item in Cache.Where(item => item.Value.Contains(c, StringComparison.InvariantCulture)))
+ {
+ var l = item.Key.First();
</code_context>
<issue_to_address>
**issue (complexity):** Consider building a reverse lookup dictionary at startup to replace repeated scans with fast dictionary access for each character.
Consider inverting `Cache` once at startup so lookups become O(1) per character instead of scanning the entire map every time:
```csharp
sealed class DefaultPinyinService : IPinyinService
{
// original Cache unchanged
static readonly Dictionary<string, string> Cache = /* … */;
// inverted map: char → List of pinyin syllables
static readonly Dictionary<char, List<string>> CharToPinyin;
static DefaultPinyinService()
{
CharToPinyin = new Dictionary<char, List<string>>();
foreach (var kv in Cache)
{
var syllable = kv.Key;
foreach (var c in kv.Value)
{
if (!CharToPinyin.TryGetValue(c, out var list))
{
list = new List<string>();
CharToPinyin[c] = list;
}
list.Add(syllable);
}
}
}
public HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory)
{
var letters = text
.Select(c => CharToPinyin.TryGetValue(c, out var p)
? p
: new List<string> { c.ToString() })
.ToList();
return CartesianProduct(letters, caseCategory, " ");
}
public HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory)
{
var letters = text
.Select(c => CharToPinyin.TryGetValue(c, out var p)
? p.Select(s => s[0].ToString()).ToList()
: new List<string> { c.ToString() })
.ToList();
return CartesianProduct(letters, caseCategory);
}
// CartesianProduct unchanged...
}
```
This moves the heavy nesting into a one‐time static constructor and replaces per‐call scans with a simple dictionary lookup.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
|
||
| sealed class DefaultPinyinService : IPinyinService | ||
| { | ||
| public HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: GetFirstLetters does not filter non-Chinese characters.
Non-Chinese characters may lead to empty segments and impact the Cartesian product logic. Please filter or handle them to ensure correct output.
Suggested implementation:
foreach (var c in text)
{
// Filter non-Chinese characters
if (IsChineseCharacter(c))
{
var segment = new List<char>();
foreach (var item in Cache.Where(item => item.Value.Contains(c, StringComparison.InvariantCulture)))
{
var l = item.Key.First();
segment.Add(l);
}
// Only add non-empty segments
if (segment.Count > 0)
{
letters.Add(segment);
}
}
} // Helper method to check if a character is Chinese
private static bool IsChineseCharacter(char c)
{
// CJK Unified Ideographs: U+4E00 to U+9FFF
return c >= 0x4E00 && c <= 0x9FFF;
}If IsChineseCharacter should be placed elsewhere (e.g., in a utility class), please move it accordingly. Also, ensure that the rest of the method logic (such as the Cartesian product) works with the filtered letters list.
| return CartesianProduct(letters, caseCategory); | ||
| } | ||
|
|
||
| public HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: GetPinyin omits a default value for caseCategory.
The implementation requires callers to specify caseCategory, which may cause inconsistencies with the interface. Please update the method signature to include a default value for caseCategory.
| : string.Join(separator, i))]; | ||
| } | ||
|
|
||
| public bool IsChinese(char c) => c >= 0x4E00 && c <= 0x9FA5; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: IsChinese only covers a subset of Chinese characters.
The current range excludes characters from Extension blocks. For broader coverage, expand the range or use a more comprehensive Unicode check.
| public bool IsChinese(char c) => c >= 0x4E00 && c <= 0x9FA5; | |
| public bool IsChinese(char c) | |
| { | |
| // CJK Unified Ideographs | |
| if (c >= 0x4E00 && c <= 0x9FFF) return true; | |
| // CJK Unified Ideographs Extension A | |
| if (c >= 0x3400 && c <= 0x4DBF) return true; | |
| // CJK Unified Ideographs Extension B | |
| if (c >= 0x20000 && c <= 0x2A6DF) return true; | |
| // CJK Unified Ideographs Extension C | |
| if (c >= 0x2A700 && c <= 0x2B73F) return true; | |
| // CJK Unified Ideographs Extension D | |
| if (c >= 0x2B740 && c <= 0x2B81F) return true; | |
| // CJK Unified Ideographs Extension E | |
| if (c >= 0x2B820 && c <= 0x2CEAF) return true; | |
| // CJK Unified Ideographs Extension F | |
| if (c >= 0x2CEB0 && c <= 0x2EBEF) return true; | |
| // CJK Unified Ideographs Extension G | |
| if (c >= 0x30000 && c <= 0x3134F) return true; | |
| return false; | |
| } |
| foreach (var c in text) | ||
| { | ||
| var segment = new List<char>(); | ||
| foreach (var item in Cache.Where(item => item.Value.Contains(c, StringComparison.InvariantCulture))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider building a reverse lookup dictionary at startup to replace repeated scans with fast dictionary access for each character.
Consider inverting Cache once at startup so lookups become O(1) per character instead of scanning the entire map every time:
sealed class DefaultPinyinService : IPinyinService
{
// original Cache unchanged
static readonly Dictionary<string, string> Cache = /* … */;
// inverted map: char → List of pinyin syllables
static readonly Dictionary<char, List<string>> CharToPinyin;
static DefaultPinyinService()
{
CharToPinyin = new Dictionary<char, List<string>>();
foreach (var kv in Cache)
{
var syllable = kv.Key;
foreach (var c in kv.Value)
{
if (!CharToPinyin.TryGetValue(c, out var list))
{
list = new List<string>();
CharToPinyin[c] = list;
}
list.Add(syllable);
}
}
}
public HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory)
{
var letters = text
.Select(c => CharToPinyin.TryGetValue(c, out var p)
? p
: new List<string> { c.ToString() })
.ToList();
return CartesianProduct(letters, caseCategory, " ");
}
public HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory)
{
var letters = text
.Select(c => CharToPinyin.TryGetValue(c, out var p)
? p.Select(s => s[0].ToString()).ToList()
: new List<string> { c.ToString() })
.ToList();
return CartesianProduct(letters, caseCategory);
}
// CartesianProduct unchanged...
}This moves the heavy nesting into a one‐time static constructor and replaces per‐call scans with a simple dictionary lookup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new pinyin service interface (IPinyinService) and its default implementation for converting Chinese characters to pinyin, supporting both upper and lowercase output. The service provides methods for extracting first letters, full pinyin, and checking for Chinese characters.
Key changes:
- Added
IPinyinServiceinterface with methods for pinyin conversion and Chinese character detection - Implemented
DefaultPinyinServicewith a comprehensive pinyin-to-character mapping cache - Integrated the service into the dependency injection container
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/BootstrapBlazor/Services/Pinyin/IPinyinService.cs |
Defines the pinyin service interface with four core methods |
src/BootstrapBlazor/Services/Pinyin/PinyinLetterCaseCategory.cs |
Enum for uppercase/lowercase letter selection |
src/BootstrapBlazor/Services/Pinyin/DefaultPinyinService.cs |
Default implementation with pinyin dictionary and conversion logic |
src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs |
Registers the pinyin service as singleton |
test/UnitTest/Services/PinyinServiceTest.cs |
Unit tests covering all service methods |
src/BootstrapBlazor/BootstrapBlazor.csproj |
Version bump to 9.11.5-beta01 |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| return CartesianProduct(letters, caseCategory); | ||
| } | ||
|
|
||
| public HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory) |
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GetPinyin method signature is missing a default parameter value for caseCategory, but the interface IPinyinService declares it with a default value of PinyinLetterCaseCategory.UppercaseLetter. The implementation should match the interface by adding = PinyinLetterCaseCategory.UppercaseLetter to the parameter.
| public HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory) | |
| public HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter) |
| /// <param name="text"></param> | ||
| /// <param name="caseCategory"></param> | ||
| /// <returns></returns> | ||
| HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter); | ||
|
|
||
| /// <summary> | ||
| /// 获得完整拼音方法 | ||
| /// </summary> | ||
| /// <param name="text"></param> | ||
| /// <param name="caseCategory"></param> | ||
| /// <returns></returns> | ||
| HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter); | ||
|
|
||
| /// <summary> | ||
| /// 判断是否为中文字符 | ||
| /// </summary> | ||
| /// <param name="c"></param> | ||
| /// <returns></returns> | ||
| bool IsChinese(char c); | ||
|
|
||
| /// <summary> | ||
| /// 判断字符串是否包含中文字符 | ||
| /// </summary> | ||
| /// <param name="text"></param> | ||
| /// <returns></returns> |
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The XML documentation for method parameters and return values is empty. Add meaningful descriptions: text should describe the input Chinese text, caseCategory should explain the letter case option, and returns should describe that it returns a set of possible pinyin combinations.
| /// <param name="text"></param> | |
| /// <param name="caseCategory"></param> | |
| /// <returns></returns> | |
| HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter); | |
| /// <summary> | |
| /// 获得完整拼音方法 | |
| /// </summary> | |
| /// <param name="text"></param> | |
| /// <param name="caseCategory"></param> | |
| /// <returns></returns> | |
| HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter); | |
| /// <summary> | |
| /// 判断是否为中文字符 | |
| /// </summary> | |
| /// <param name="c"></param> | |
| /// <returns></returns> | |
| bool IsChinese(char c); | |
| /// <summary> | |
| /// 判断字符串是否包含中文字符 | |
| /// </summary> | |
| /// <param name="text"></param> | |
| /// <returns></returns> | |
| /// <param name="text">The input Chinese text to convert to pinyin initials.</param> | |
| /// <param name="caseCategory">Specifies the letter case option for the pinyin output.</param> | |
| /// <returns>A set of possible pinyin initial combinations for the input text.</returns> | |
| HashSet<string> GetFirstLetters(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter); | |
| /// <summary> | |
| /// 获得完整拼音方法 | |
| /// </summary> | |
| /// <param name="text">The input Chinese text to convert to full pinyin.</param> | |
| /// <param name="caseCategory">Specifies the letter case option for the pinyin output.</param> | |
| /// <returns>A set of possible full pinyin combinations for the input text.</returns> | |
| HashSet<string> GetPinyin(string text, PinyinLetterCaseCategory caseCategory = PinyinLetterCaseCategory.UppercaseLetter); | |
| /// <summary> | |
| /// 判断是否为中文字符 | |
| /// </summary> | |
| /// <param name="c">The character to check.</param> | |
| /// <returns><c>true</c> if the character is a Chinese character; otherwise, <c>false</c>.</returns> | |
| bool IsChinese(char c); | |
| /// <summary> | |
| /// 判断字符串是否包含中文字符 | |
| /// </summary> | |
| /// <param name="text">The string to check for Chinese characters.</param> | |
| /// <returns><c>true</c> if the string contains any Chinese characters; otherwise, <c>false</c>.</returns> |
| /// <param name="text"></param> | ||
| /// <param name="caseCategory"></param> | ||
| /// <returns></returns> |
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The XML documentation for method parameters and return values is empty. Add meaningful descriptions: text should describe the input Chinese text, caseCategory should explain the letter case option, and returns should describe that it returns a set of complete pinyin strings.
| /// <param name="text"></param> | |
| /// <param name="caseCategory"></param> | |
| /// <returns></returns> | |
| /// <param name="text">The input Chinese text to be converted to pinyin.</param> | |
| /// <param name="caseCategory">Specifies the letter case option for the pinyin output.</param> | |
| /// <returns>Returns a set of complete pinyin strings corresponding to the input text.</returns> |
| /// <param name="c"></param> | ||
| /// <returns></returns> |
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The XML documentation for the parameter and return value is empty. Add meaningful descriptions: c should describe that it's the character to check, and returns should explain that it returns true if the character is Chinese.
| /// <param name="c"></param> | |
| /// <returns></returns> | |
| /// <param name="c">The character to check.</param> | |
| /// <returns>True if the character is Chinese; otherwise, false.</returns> |
| /// <param name="text"></param> | ||
| /// <returns></returns> |
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The XML documentation for the parameter and return value is empty. Add meaningful descriptions: text should describe the input string to check, and returns should explain that it returns true if any character in the string is Chinese.
| /// <param name="text"></param> | |
| /// <returns></returns> | |
| /// <param name="text">The input string to check for Chinese characters.</param> | |
| /// <returns>True if any character in the string is Chinese; otherwise, false.</returns> |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6968 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 740 741 +1
Lines 31900 32343 +443
Branches 4473 4481 +8
==========================================
+ Hits 31900 32343 +443
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Link issues
fixes #6967
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Introduce a pinyin conversion feature by defining IPinyinService and its enum, implementing DefaultPinyinService with an internal character cache, registering it in DI, and adding tests to verify its functionality.
New Features: