| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
共有 780 人关注过本帖
标题:挑战DeepSeek!感觉上,TA写VFP代码没太大问题啊。
取消只看楼主 加入收藏
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
结帖率:100%
收藏
 问题点数:0 回复次数:8 
挑战DeepSeek!感觉上,TA写VFP代码没太大问题啊。
提问:
StrExtract(x,"<",">")可以提取两个分隔符之间的字符串,请实现函数StrDelExtract(x,"<",">"),用途是删除两个分隔符之间的字符串(类似于批量删除<XML>标签一类操作)。

回答:
FUNCTION StrDelExtract(cString, cBeginDelim, cEndDelim)
    LOCAL nStartPos, nEndPos, cResult, i, nOccurrence
   
    * 参数检查
    IF VARTYPE(cString) <> "C" OR EMPTY(cString)
        RETURN ""
    ENDIF
    IF VARTYPE(cBeginDelim) <> "C" OR EMPTY(cBeginDelim)
        RETURN cString
    ENDIF
    IF VARTYPE(cEndDelim) <> "C" OR EMPTY(cEndDelim)
        RETURN cString
    ENDIF
    nOccurrence = OCCURS(cBeginDelim, cString)  && 统计匹配数目
    IF nOccurrence = 0
        RETURN cString
    ENDIF
   
    * 初始化
    cResult = cString
   
    * 循环处理所有匹配项
    for i = 1 to nOccurrence
        nStartPos = AT(cBeginDelim, cResult)
        nEndPos = AT(cEndDelim, cResult)
        IF nEndPos = 0
            EXIT
        ENDIF
        * 删除匹配部分
        cResult = STUFF(cResult, nStartPos, nEndPos - nStartPos + LEN(cEndDelim), "")      
    ENDFOR i
   
    RETURN cResult
ENDFUNC

*---------------*
DeepSeek的原始代码用Do...while,随手改为For...Endfor,TA写的这段VFP代码,似乎也没啥好再优化的了。
搜索更多相关主题的帖子: 代码 cString IF RETURN VFP 
2025-04-13 12:51
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
当然,有些容错,TA还是写漏了,比如:
假设我故意将分隔符写成>xxx<,又或者,写成<<xxx>>,又或者……AI毕竟斗不过险恶的人心哪。嘿嘿。


2025-04-13 14:18
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
TA还提供了更简洁的正则表达式(复杂匹配):

* 需引用 VBScript.RegExp
oRegEx = CREATEOBJECT("VBScript.RegExp")
oRegEx.Pattern = "\<.*?\>"  && 非贪婪匹配<...>
oRegEx.Global = .T.
cResult = oRegEx.Replace(cString, "")
……

只是,在我心目中,这样一个函数可能会这么用:

replace all content with StrDelExtract(content,"<",">")

在成千上万行记录中,创建成千上万次对象"VBScript.RegExp",然后再成千上万次销毁,感觉上总有些莫名的奢侈。
摇摇头心想还是算了罢。


2025-04-13 15:08
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
以下是引用csyx在2025-4-13 15:40:12的发言:
你就不能把函数改下?先创建并设置好 oRegEx,然后作为参数传给 StrDelExtract
再或者,创建一个 goRegEx,省得还要传入


这……这……这,假假地,这也算一个通用函数吧?要求调用者事先创建一个oRegEx,然后再调用,万一不留神,忘了这茬咧?这“复用性”……未免也太过强人所难了吧?
2025-04-13 17:43
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
参照DeepSeek的回答,我也挖空心思实现了另一个版本,只可惜忘了妥善处理分隔符嵌套的情形

FUNCTION StrExcise(cString, cBeginDelim, cEndDelim)
    LOCAL nStartPos, nEndPos, cResult, i, nOccurrence
   
    * 参数检查
    IF VARTYPE(cString) <> "C" OR EMPTY(cString)
        RETURN ""
    ENDIF
    IF VARTYPE(cBeginDelim) <> "C" OR EMPTY(cBeginDelim)
        RETURN cString
    ENDIF
    IF VARTYPE(cEndDelim) <> "C" OR EMPTY(cEndDelim)
        RETURN cString
    ENDIF
    nOccurrence = OCCURS(cBeginDelim, cString)  && 统计匹配数目
    IF nOccurrence = 0
        RETURN cString
    ENDIF
   
    * 分割源字符串
    nLines = alines(a_lines, cString, 16, cBeginDelim, cEndDelim, 0h0D0A)
    * 初始化
    cResult = ""

    * 循环处理所有匹配项
    for i=1 to nLines
        nStartPos = AT(cBeginDelim, a_lines[i])
        nEndPos = AT(cEndDelim, a_lines[i])
    Do case
        case nStartPos > 0
           cResult = cResult + left(a_lines[i], nStartPos-1)
        case nEndPos > 0
        otherwise
           cResult = cResult + a_lines[i] + 0h0D0A
        Endcase
    ENDFOR i
   
    RETURN cResult
ENDFUNC

2025-04-13 21:55
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
第二个问题受7#启发,相对简单些:
函数strTran(x,"<",">")可以批量删除或替换字符表达式或备注字段中的关键字,请实现函数LineTran(),用途是,将字符表达式或备注字段中含有关键字的一整行,批量替换或删除。

回答:
FUNCTION LineTran(cMemoText, cKeyLine, cReplaceTo)
    LOCAL cResult, nLineCount, i, cLine
   
    * 参数检查
    IF VARTYPE(cMemoText) <> "C" OR EMPTY(cMemoText)
        RETURN ""
    ENDIF
    IF VARTYPE(cKeyLine) <> "C" OR EMPTY(cKeyLine)
        RETURN cMemoText
    ENDIF
    IF VARTYPE(cReplaceTo) <> "C"
        cReplaceTo = ""
    ENDIF
   
    * 按行处理
    cResult = ""
    nLineCount = ALINES(a_Lines, cMemoText)
   
    FOR i = 1 TO nLineCount
        cLine = a_Lines[i]
        * 判断是否包含关键字(区分大小写)
        IF at(cKeyLine, cLine) > 0
        if ! empty(cReplaceTo)
        cResult = cResult + cReplaceTo + IIF(i < nLineCount, CHR(13) + CHR(10), "")
        endif
        ELSE
            cResult = cResult + cLine + IIF(i < nLineCount, CHR(13) + CHR(10), "")
        ENDIF
    ENDFOR
   
    RETURN cResult
ENDFUNC

*---------------*
注:同上,DeepSeek的原始代码用Do...while,随手改为For...Endfor。
2025-04-14 10:42
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
问:
设“金银花”的配料表为“胆酸 珍珠母 栀子 水牛角 板蓝根 黄芩苷”,“板蓝根”的配料表为“麻黄 地龙 胆酸 栀子 五味子 黄芩苷 蝉蜕 金银花 ”,用VFP实现一个函数,计算两个输入参数(以空格作为分隔符的字符串)的匹配度。

答:
*-----注:DeepSeek给出的代码,个别行可能有误!------*
FUNCTION IngredientMatch
LPARAMETERS tcList1, tcList2
    * 函数功能:计算两个配料表的匹配度
    * 参数:tcList1 - 第一个配料表字符串(空格分隔)
    *       tcList2 - 第二个配料表字符串(空格分隔)
    * 返回值:匹配度百分比(0-100)
   
    * 分割字符串为数组
    LOCAL lnCount1, lnCount2, lnMatchCount, i, j
    LOCAL ARRAY laList1[1], laList2[1]
   
    * 分割第一个配料表
    lnCount1 = ALINES(laList1, STRTRAN(ALLTRIM(tcList1), "  ", " "))
    lnCount1 = ALINES(laList1, tcList1, " ")
   
    * 分割第二个配料表
    lnCount2 = ALINES(laList2, STRTRAN(ALLTRIM(tcList2), "  ", " ")
    lnCount2 = ALINES(laList2, tcList2, " ")
   
    * 计算匹配的配料数量
    lnMatchCount = 0
   
    * 检查laList1中的配料是否在laList2中
    FOR i = 1 TO lnCount1
        FOR j = 1 TO lnCount2
            IF UPPER(ALLTRIM(laList1[i])) == UPPER(ALLTRIM(laList2[j]))
                lnMatchCount = lnMatchCount + 1
                EXIT
            ENDIF
        ENDFOR
    ENDFOR
   
    * 计算匹配度百分比(基于两个列表的平均长度)
    LOCAL lnAvgLength, lnMatchPercent
    lnAvgLength = (lnCount1 + lnCount2) / 2
   
    IF lnAvgLength > 0
        lnMatchPercent = (lnMatchCount / lnAvgLength) * 100
    ELSE
        lnMatchPercent = 0
    ENDIF
   
    * 四舍五入到两位小数
    lnMatchPercent = ROUND(lnMatchPercent, 2)
   
    RETURN lnMatchPercent
ENDFUNC


2025-04-26 14:25
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
问:
设配料表中的子配料,如“胆酸”,也由若干配料构成:“栀子 地龙 麻黄 前胡 枇杷叶”,“黄芩苷”的配料:“牛蒡子 胆酸 麻黄 紫苏”……,重构此函数,以类递归方式计算出更复杂的匹配度。

答:
<略>

问:
上面的函数以纯数组方式实现,无疑将问题复杂化了。现改用数据表Ingredient.dbf储存3000多种子配料信息,表结构为3个字段:name C (20),detail M,ID I。字段name是子配料名称,字段detail是以空格分隔的具体的子配料字符串,字段ID是整型数值。递归遍历此1000多种子配料表,若计算得到2个、3个、4个……或更多的子配料匹配度>=66.66%,则将其ID设为相同数值,即,将同一类的子配料,归为同一组。请重构函数,实现此算法。

答:
*----------注:deepSeek给出的代码有些复杂,我老人家此刻正在研读中……
*-- 主函数:配料匹配与分组
FUNCTION GroupIngredients
LPARAMETERS tnThreshold
    * 参数:tnThreshold - 分组匹配度阈值(51%)
    * 功能:递归分析配料表,将匹配度>=阈值的配料归为同一组
   
    LOCAL lnGroupID, lcSQL, lnCount
   
    * 初始化分组ID
    SELECT MAX(ID) FROM Ingredient INTO ARRAY laMaxID
    lnGroupID = IIF(ISNULL(laMaxID[1]), 1, laMaxID[1] + 1)
   
    * 创建临时表存储匹配结果
    CREATE CURSOR TempMatches (;
        Name1 C(20),;
        Name2 C(20),;
        MatchPercent N(5,2);
    )
   
    * 比较所有配料组合
    lcSQL = "SELECT A.Name AS Name1, B.Name AS Name2 ";
          + "FROM Ingredient A, Ingredient B ";
          + "WHERE A.Name < B.Name"  // 避免重复比较
   
    &lcSQL INTO CURSOR TempPairs
   
    SELECT TempPairs
    SCAN
        * 计算两个配料的匹配度
        lnMatch = CalculateMatch(TempPairs.Name1, TempPairs.Name2)
        
        * 存储匹配结果
        INSERT INTO TempMatches VALUES ;
            (TempPairs.Name1, TempPairs.Name2, lnMatch)
    ENDSCAN
   
    * 根据匹配结果分组
    SELECT * FROM TempMatches ;
        WHERE MatchPercent >= tnThreshold ;
        ORDER BY MatchPercent DESC ;
        INTO CURSOR TempValidMatches
   
    SELECT TempValidMatches
    SCAN
        * 查找两个配料的当前组ID
        LOCAL lnID1, lnID2
        SELECT ID FROM Ingredient WHERE Name = TempValidMatches.Name1 INTO ARRAY laID1
        SELECT ID FROM Ingredient WHERE Name = TempValidMatches.Name2 INTO ARRAY laID2
        
        lnID1 = IIF(_TALLY > 0, laID1[1], 0)
        lnID2 = IIF(_TALLY > 0, laID2[1], 0)
        
        * 分组逻辑
        DO CASE
        CASE lnID1 = 0 AND lnID2 = 0
            * 两个配料都未分组,赋予新组ID
            UPDATE Ingredient SET ID = lnGroupID ;
                WHERE Name = TempValidMatches.Name1 OR Name = TempValidMatches.Name2
            lnGroupID = lnGroupID + 1
            
        CASE lnID1 = 0
            * 配料1未分组,加入配料2的组
            UPDATE Ingredient SET ID = lnID2 WHERE Name = TempValidMatches.Name1
            
        CASE lnID2 = 0
            * 配料2未分组,加入配料1的组
            UPDATE Ingredient SET ID = lnID1 WHERE Name = TempValidMatches.Name2
            
        CASE lnID1 <> lnID2
            * 两个配料属于不同组,合并两组
            UPDATE Ingredient SET ID = lnID1 WHERE ID = lnID2
        ENDCASE
    ENDSCAN
   
    * 返回分组数量
    SELECT COUNT(DISTINCT ID) FROM Ingredient WHERE ID > 0 INTO ARRAY laGroupCount
    RETURN laGroupCount[1]
ENDFUNC

*-- 递归计算两个配料的匹配度
FUNCTION CalculateMatch
LPARAMETERS tcName1, tcName2, tnDepth
    * 参数:tcName1, tcName2 - 要比较的配料名称
    *       tnDepth - 当前递归深度
   
    * 初始化参数
    tnDepth = IIF(EMPTY(tnDepth), 1, tnDepth)
    IF tnDepth > 5  && 限制递归深度
        RETURN 0
    ENDIF
   
    * 获取配料详情
    LOCAL lcDetail1, lcDetail2
    SELECT detail FROM Ingredient WHERE Name = tcName1 INTO ARRAY laDetail1
    SELECT detail FROM Ingredient WHERE Name = tcName2 INTO ARRAY laDetail2
   
    lcDetail1 = IIF(_TALLY > 0, laDetail1[1], "")
    lcDetail2 = IIF(_TALLY > 0, laDetail2[1], "")
   
    * 如果都没有子配料,直接比较名称
    IF EMPTY(lcDetail1) AND EMPTY(lcDetail2)
        RETURN IIF(UPPER(tcName1) == UPPER(tcName2), 100, 0)
    ENDIF
   
    * 分割子配料
    LOCAL lnCount1, lnCount2, lnMatchCount, i, j
    LOCAL ARRAY laItems1[1], laItems2[1]
   
    lnCount1 = ALINES(laItems1, lcDetail1, " ")
    lnCount2 = ALINES(laItems2, lcDetail2, " ")
   
    * 计算直接匹配
    lnMatchCount = 0
    FOR i = 1 TO lnCount1
        FOR j = 1 TO lnCount2
            IF UPPER(ALLTRIM(laItems1[i])) == UPPER(ALLTRIM(laItems2[j]))
                lnMatchCount = lnMatchCount + 1
                EXIT
            ENDIF
        ENDFOR
    ENDFOR
   
    * 计算递归匹配
    LOCAL lnRecursiveMatch, lnTotalWeight
    lnRecursiveMatch = 0
    lnTotalWeight = 0
   
    FOR i = 1 TO lnCount1
        FOR j = 1 TO lnCount2
            * 跳过已直接匹配的
            IF UPPER(ALLTRIM(laItems1[i])) == UPPER(ALLTRIM(laItems2[j]))
                LOOP
            ENDIF
            
            * 计算子配料匹配度
            LOCAL lnSubMatch
            lnSubMatch = CalculateMatch(laItems1[i], laItems2[j], tnDepth + 1)
            
            * 加权累加
            IF lnSubMatch > 0
                lnRecursiveMatch = lnRecursiveMatch + lnSubMatch
                lnTotalWeight = lnTotalWeight + 1
            ENDIF
        ENDFOR
    ENDFOR
   
    * 计算总匹配度
    LOCAL lnTotalMatch, lnAvgLength
    lnAvgLength = (lnCount1 + lnCount2) / 2
   
    IF lnTotalWeight > 0
        lnRecursiveMatch = lnRecursiveMatch / lnTotalWeight  && 平均递归匹配度
    ENDIF
   
    lnTotalMatch = lnMatchCount + lnRecursiveMatch
   
    IF lnAvgLength > 0
        lnTotalMatch = (lnTotalMatch / lnAvgLength) * 100
    ELSE
        lnTotalMatch = 0
    ENDIF
   
    RETURN ROUND(lnTotalMatch, 2)
ENDFUNC

2025-04-26 14:29
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:376
专家分:360
注 册:2013-10-4
收藏
得分:0 
讲真,13#的算法比较复杂,我只是突发奇想设计了一个古怪题目,结果DeepSeek毫不费力将代码写出来了。

想要看懂这段代码,还真不是件容易的事情!再者,我手头也并没有数据表去测试DeepSeek实现的函数。

若挑战的不是DeepSeek,而是人,能秒提供一份更好的算法方案吗?
2025-04-26 16:41
快速回复:挑战DeepSeek!感觉上,TA写VFP代码没太大问题啊。
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.563309 second(s), 9 queries.
Copyright©2004-2025, BC-CN.NET, All Rights Reserved