Skip to content

Commit ed6f4b9

Browse files
author
linzhijun
committed
fix
1 parent 40078a6 commit ed6f4b9

9 files changed

Lines changed: 162 additions & 24 deletions

File tree

‎JavaScript/src/Internals/Functions/Csharp/Function_GUID.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ export class Function_GUID extends FunctionBase {
3333
let r = Math.random() * 16 | 0;
3434
let v = c === 'x' ? r : (r & 0x3 | 0x8);
3535
return v.toString(16);
36-
}).toUpperCase();
36+
});
3737
}
3838

3939

4040
toString2(stringBuilder, addBrackets) {
41-
stringBuilder.push("GUID()");
41+
stringBuilder.push("Guid()");
4242
}
4343
}
4444

‎JavaScript/src/Internals/Functions/Csharp/Function_LASTINDEXOF.js‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ export class Function_LASTINDEXOF extends Function_4 {
2828
if (args2.IsError) { return args2; }
2929

3030
let text = args1.TextValue;
31+
let searchStr = args2.TextValue;
3132
if (this.c == null) {
32-
let index = text.lastIndexOf(args2.TextValue);
33+
let index = text.lastIndexOf(searchStr);
3334
return Operand.Create(index + engine.ExcelIndex);
3435
}
3536

@@ -42,7 +43,15 @@ export class Function_LASTINDEXOF extends Function_4 {
4243
}
4344

4445
if (this.d == null) {
45-
let index = text.substring(0, startIndex).lastIndexOf(args2.TextValue);
46+
// C# LastIndexOf(str, startIndex): 匹配的最后一个字符位置 ≤ startIndex
47+
// JS lastIndexOf(str, fromIndex): 匹配的第一个字符位置 ≤ fromIndex
48+
// 转换: fromIndex = startIndex - searchStr.length + 1
49+
let fromIndex = startIndex - searchStr.length + 1;
50+
// JS 对负数 fromIndex 会将其视为 0 搜索整个字符串,需手动返回 -1
51+
if (fromIndex < 0 && searchStr.length > 0) {
52+
return Operand.Create(-1 + engine.ExcelIndex);
53+
}
54+
let index = text.lastIndexOf(searchStr, fromIndex);
4655
return Operand.Create(index + engine.ExcelIndex);
4756
}
4857

@@ -54,8 +63,10 @@ export class Function_LASTINDEXOF extends Function_4 {
5463
return this.parameterError(4);
5564
}
5665

66+
// C# LastIndexOf(str, startIndex, count): 在 [startIndex-count+1, startIndex] 窗口内搜索
67+
// 使用 substring 窗口法确保语义一致
5768
let offset = startIndex - count + 1;
58-
let localIndex = text.substring(offset, startIndex + 1).lastIndexOf(args2.TextValue);
69+
let localIndex = text.substring(offset, startIndex + 1).lastIndexOf(searchStr);
5970
let index = localIndex === -1 ? -1 : localIndex + offset;
6071
return Operand.Create(index + engine.ExcelIndex);
6172
}

‎csharp/ToolGood.Algorithm.Test/AlgorithmEngine/CsharpTest.cs‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,125 @@ public void HasValue_test()
549549
dt = engine.TryEvaluate("HasValue(json('[1,2,3]'),'2')", false);
550550
Assert.AreEqual(dt, true);
551551
}
552+
553+
[Test]
554+
public void LastIndexOf_with_startIndex_test()
555+
{
556+
AlgorithmEngine engine = new AlgorithmEngine();
557+
engine.UseExcelIndex = false;
558+
559+
// 单字符在 startIndex 位置能被找到(修复 AsSpan off-by-one bug:
560+
// 原 AsSpan(0,startIndex) 缺少 startIndex 位置的字符)
561+
var dt = engine.TryEvaluate("LastIndexOf('abc','c',2)", -1);
562+
Assert.AreEqual(dt, 2);
563+
564+
// 多字符匹配的最后一个字符恰好在 startIndex 位置
565+
dt = engine.TryEvaluate("LastIndexOf('abcd','cd',3)", -1);
566+
Assert.AreEqual(dt, 2);
567+
568+
// startIndex 之前有更早的匹配
569+
dt = engine.TryEvaluate("LastIndexOf('abcdcd','cd',3)", -1);
570+
Assert.AreEqual(dt, 2);
571+
572+
// startIndex == text.Length 允许(搜索到末尾)
573+
dt = engine.TryEvaluate("LastIndexOf('abcdcd','cd',6)", -1);
574+
Assert.AreEqual(dt, 4);
575+
576+
// startIndex 窗口内无匹配(匹配延伸到 startIndex 之外)
577+
dt = engine.TryEvaluate("LastIndexOf('ababa','aba',2)", -1);
578+
Assert.AreEqual(dt, 0);
579+
580+
// 完全未找到
581+
dt = engine.TryEvaluate("LastIndexOf('abcd','xyz',2)", -1);
582+
Assert.AreEqual(dt, -1);
583+
584+
// 1-based Excel index: 参数 startIndex=3 → 0-based=2
585+
engine.UseExcelIndex = true;
586+
dt = engine.TryEvaluate("LastIndexOf('abc','c',3)", -1);
587+
Assert.AreEqual(dt, 3);
588+
}
589+
590+
[Test]
591+
public void LastIndexOf_with_startIndex_and_count_test()
592+
{
593+
AlgorithmEngine engine = new AlgorithmEngine();
594+
engine.UseExcelIndex = false;
595+
596+
// 4参数:文本、搜索串、起始位置、count —— 窗口内匹配
597+
var dt = engine.TryEvaluate("LastIndexOf('abcabcabc','abc',5,3)", -1);
598+
Assert.AreEqual(dt, 3);
599+
600+
// count 覆盖整个字符串(startIndex=8, count=9 → 窗口[0,8])
601+
dt = engine.TryEvaluate("LastIndexOf('abcabcabc','abc',8,9)", -1);
602+
Assert.AreEqual(dt, 6);
603+
604+
// count 受限,找不到更近的匹配
605+
dt = engine.TryEvaluate("LastIndexOf('abcabcabc','abc',5,2)", -1);
606+
Assert.AreEqual(dt, -1);
607+
}
608+
609+
[Test]
610+
public void LastIndexOf_not_found_with_startIndex_test()
611+
{
612+
AlgorithmEngine engine = new AlgorithmEngine();
613+
engine.UseExcelIndex = false;
614+
615+
// startIndex 窗口内没有匹配项
616+
var dt = engine.TryEvaluate("LastIndexOf('abcdef','xyz',3)", -1);
617+
Assert.AreEqual(dt, -1);
618+
}
619+
620+
[Test]
621+
public void Guid_test()
622+
{
623+
AlgorithmEngine engine = new AlgorithmEngine();
624+
var dt = engine.TryEvaluate("Guid()", null);
625+
Assert.IsNotNull(dt);
626+
Assert.IsTrue(dt is string);
627+
// GUID 格式: 8-4-4-4-12
628+
Assert.AreEqual(((string)dt).Length, 36);
629+
}
630+
631+
[Test]
632+
public void Has_json_array_types_test()
633+
{
634+
AlgorithmEngine engine = new AlgorithmEngine();
635+
636+
// JSON 数组包含 double 类型值
637+
var dt = engine.TryEvaluate("Has(json('[1,2,3]'),'2')", false);
638+
Assert.AreEqual(dt, true);
639+
640+
// JSON 数组包含 boolean 类型值
641+
dt = engine.TryEvaluate("Has(json('[true,false]'),'true')", false);
642+
Assert.AreEqual(dt, true);
643+
644+
dt = engine.TryEvaluate("Has(json('[true,false]'),'false')", false);
645+
Assert.AreEqual(dt, true);
646+
647+
// JSON 对象按键查找
648+
dt = engine.TryEvaluate("Has(json('{\"a\":1,\"b\":2}'),'a')", false);
649+
Assert.AreEqual(dt, true);
650+
651+
dt = engine.TryEvaluate("Has(json('{\"a\":1,\"b\":2}'),'c')", false);
652+
Assert.AreEqual(dt, false);
653+
}
654+
655+
[Test]
656+
public void HasValue_json_array_types_test()
657+
{
658+
AlgorithmEngine engine = new AlgorithmEngine();
659+
660+
// JSON 数组包含 double 类型值
661+
var dt = engine.TryEvaluate("HasValue(json('[1,2,3]'),'2')", false);
662+
Assert.AreEqual(dt, true);
663+
664+
// JSON 对象包含 boolean 类型值
665+
dt = engine.TryEvaluate("HasValue(json('{\"a\":true,\"b\":false}'),'true')", false);
666+
Assert.AreEqual(dt, true);
667+
668+
dt = engine.TryEvaluate("HasValue(json('{\"a\":true,\"b\":false}'),'false')", false);
669+
Assert.AreEqual(dt, true);
670+
}
552671

553672
}
554673
}

‎csharp/ToolGood.Algorithm/Internals/Functions/Csharp/Function_GUID.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Text;
33
using ToolGood.Algorithm.Enums;
44

@@ -19,7 +19,7 @@ public override Operand Evaluate(AlgorithmEngine engine, Func<AlgorithmEngine, s
1919
}
2020
public override void ToString(StringBuilder stringBuilder, bool addBrackets)
2121
{
22-
stringBuilder.Append("GUID()");
22+
stringBuilder.Append("Guid()");
2323
}
2424
public override OperandType GetResultType()
2525
{

‎csharp/ToolGood.Algorithm/Internals/Functions/Csharp/Function_HAS.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public override Operand Evaluate(AlgorithmEngine engine, Func<AlgorithmEngine, s
3636
if(v.IsString) {
3737
if(v.StringValue == args2.TextValue) { return Operand.True; }
3838
} else if(v.IsDouble) {
39-
if(v.NumberValue.ToString(CultureInfo.InvariantCulture) == args2.TextValue) { return Operand.True; }
39+
if(v.NumberValue.ToString(CultureInfo.InvariantCulture) == args2.TextValue) { return Operand.True; }
4040
} else if(v.IsBoolean) {
4141
if(v.BooleanValue.ToString().Equals(args2.TextValue, StringComparison.CurrentCultureIgnoreCase)) { return Operand.True; }
4242
}

‎csharp/ToolGood.Algorithm/Internals/Functions/Csharp/Function_LASTINDEXOF.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public override Operand Evaluate(AlgorithmEngine engine, Func<AlgorithmEngine, s
3636
}
3737

3838
if(func4 == null) {
39-
return Operand.Create(text.AsSpan(0, startIndex).LastIndexOf(args2.TextValue) + engine.ExcelIndex);
39+
return Operand.Create(text.LastIndexOf(args2.TextValue, startIndex) + engine.ExcelIndex);
4040
}
4141

4242
var args4 = GetNumber_4(engine, tempParameter);

‎java/toolgood.algorithm/src/main/java/toolgood/algorithm/internals/functions/csharp/Function_GUID.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public Operand Evaluate(AlgorithmEngine engine, BiFunction<AlgorithmEngine, Stri
2424

2525
@Override
2626
public void ToString(StringBuilder stringBuilder, boolean addBrackets) {
27-
stringBuilder.append("GUID()");
27+
stringBuilder.append("Guid()");
2828
}
2929

3030
@Override

‎java/toolgood.algorithm/src/main/java/toolgood/algorithm/internals/functions/csharp/Function_INDEXOF.java‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ public Operand Evaluate(AlgorithmEngine engine, BiFunction<AlgorithmEngine, Stri
3737
}
3838

3939
String text = args1.TextValue();
40+
String searchStr = args2.TextValue();
4041
int excelIndex = engine.ExcelIndex;
4142

4243
if (func3 == null) {
43-
return Operand.Create(text.indexOf(args2.TextValue()) + excelIndex);
44+
return Operand.Create(text.indexOf(searchStr) + excelIndex);
4445
}
4546

4647
Operand args3 = GetNumber_3(engine, tempParameter);
@@ -53,7 +54,7 @@ public Operand Evaluate(AlgorithmEngine engine, BiFunction<AlgorithmEngine, Stri
5354
}
5455

5556
if (func4 == null) {
56-
return Operand.Create(text.indexOf(args2.TextValue(), startIndex) + excelIndex);
57+
return Operand.Create(text.indexOf(searchStr, startIndex) + excelIndex);
5758
}
5859

5960
Operand args4 = GetNumber_4(engine, tempParameter);
@@ -65,11 +66,11 @@ public Operand Evaluate(AlgorithmEngine engine, BiFunction<AlgorithmEngine, Stri
6566
return ParameterError(4);
6667
}
6768

68-
int idx = text.indexOf(args2.TextValue(), startIndex);
69-
if (idx >= 0 && idx < startIndex + count) {
70-
return Operand.Create(idx + excelIndex);
71-
}
72-
return Operand.Create(-1 + excelIndex);
69+
// C# IndexOf(str, startIndex, count): 匹配必须完全在 [startIndex, startIndex+count) 窗口内
70+
// 使用 substring 窗口法确保语义一致
71+
int localIdx = text.substring(startIndex, startIndex + count).indexOf(searchStr);
72+
int idx = localIdx == -1 ? -1 : localIdx + startIndex;
73+
return Operand.Create(idx + excelIndex);
7374
}
7475

7576
@Override

‎java/toolgood.algorithm/src/main/java/toolgood/algorithm/internals/functions/csharp/Function_LASTINDEXOF.java‎

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ public Operand Evaluate(AlgorithmEngine engine, BiFunction<AlgorithmEngine, Stri
3737
}
3838

3939
String text = args1.TextValue();
40+
String searchStr = args2.TextValue();
4041
int excelIndex = engine.ExcelIndex;
4142

4243
if (func3 == null) {
43-
return Operand.Create(text.lastIndexOf(args2.TextValue()) + excelIndex);
44+
return Operand.Create(text.lastIndexOf(searchStr) + excelIndex);
4445
}
4546

4647
Operand args3 = GetNumber_3(engine, tempParameter);
@@ -53,7 +54,11 @@ public Operand Evaluate(AlgorithmEngine engine, BiFunction<AlgorithmEngine, Stri
5354
}
5455

5556
if (func4 == null) {
56-
return Operand.Create(text.substring(0, startIndex).lastIndexOf(args2.TextValue()) + excelIndex);
57+
// C# LastIndexOf(str, startIndex): 匹配的最后一个字符位置 ≤ startIndex
58+
// Java lastIndexOf(str, fromIndex): 匹配的第一个字符位置 ≤ fromIndex
59+
// 转换: fromIndex = startIndex - searchStr.length() + 1
60+
int fromIndex = startIndex - searchStr.length() + 1;
61+
return Operand.Create(text.lastIndexOf(searchStr, fromIndex) + excelIndex);
5762
}
5863

5964
Operand args4 = GetNumber_4(engine, tempParameter);
@@ -65,11 +70,13 @@ public Operand Evaluate(AlgorithmEngine engine, BiFunction<AlgorithmEngine, Stri
6570
return ParameterError(4);
6671
}
6772

68-
int idx = text.lastIndexOf(args2.TextValue(), startIndex);
69-
if (idx >= 0 && idx >= startIndex - count + 1) {
70-
return Operand.Create(idx + excelIndex);
71-
}
72-
return Operand.Create(-1 + excelIndex);
73+
// C# LastIndexOf(str, startIndex, count): 在 [startIndex-count+1, startIndex] 窗口内搜索
74+
// 使用 substring 窗口法确保语义一致
75+
int offset = startIndex - count + 1;
76+
int endPos = Math.min(startIndex + 1, text.length());
77+
int localIdx = text.substring(offset, endPos).lastIndexOf(searchStr);
78+
int idx = localIdx == -1 ? -1 : localIdx + offset;
79+
return Operand.Create(idx + excelIndex);
7380
}
7481

7582
@Override

0 commit comments

Comments
 (0)