ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 3651|回复: 25

[分享] 选枝随机、答案调整,已解决。

[复制链接]

TA的精华主题

TA的得分主题

发表于 2020-4-12 20:16 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 weiyingde 于 2020-5-6 07:31 编辑

声明:
1、下面的程序代码原创始于duquancai杜大侠,见http://club.excelhome.net/thread-384424-1-2.html第五楼
    创意亦始于sylun大侠的“试卷试题随机排序”的帖子。见http://club.excelhome.net/thread-385342-1-1.html,所以这个帖子,不是我的原创作品。
2、sylun大侠的代码,比较复杂,想探究,终因缺乏耐心而未能卒读;杜大侠的代码精练、流畅,作为我首选学习模仿;但杜大侠的代码只有一项功能,不能完全实现我的要求。所以,我在他的代码基础上加以补充,实现了更新调整答案,可就在实现更新“【解析】”中序号的时候又卡壳了……
3、这个帖子是http://club.excelhome.net/thread-1530951-1-1.html帖子的延续,本该在该帖子下继续跟帖,又怕因此而泥牛入海,杳无音信……为吹箫引凤,只好另外开贴。
4、本帖子虽是改编,但由于本人半路出家、才疏学浅、思维缓慢闭塞……到目前程度,几历构思、修改、调试……已经花费了两天时间,至此环节,山穷水尽……期盼高人行家指点,帮老朽走出迷宫……

再次期盼大侠的出现………………………………

代码如下:

Sub 综合简约实验版()
    Dim mt, mk, oRng As Range, n&, m&, str$, TT$
    Dim rg As Range, arr(), x%, d As Object, k&, ar, rng1 As Range, rng2 As Range
    Set d = CreateObject("Scripting.Dictionary")
    Set dic = CreateObject("Scripting.Dictionary")
    Set RegE = CreateObject("vbscript.regexp")
    RegE.Pattern = "[\((][A-Z]{1,}[\))](?:\r)"
    Set RegX = CreateObject("vbscript.regexp")
    RegX.Pattern = "【解析】.*"
    RegX.Global = False
    On Error Resume Next
   
    str = Replace(ActiveDocument.Content, Chr(7), "")
    With CreateObject("vbscript.regexp")
        .Global = True: .IgnoreCase = False: .MultiLine = True
        
        Rem 说明:
        Rem 下面的.Pattern用非注释的能顺利实现:
        Rem    ⑴选枝随机;⑵括号的答案能顺利与随机选枝做相应调整更新。
        Rem  遗憾:不能实现【解析】里出现的编号(A.B.C.D)不能与选枝作相应调整。
        Rem  原因:为了实现实现上面的两项功能,故意屏蔽了【解析】段,带来RegX.Pattern = "【解析】.*"不能匹配到目标。
        Rem  探索:将下面两处的注释和非注释轮换如何?出现两个问题。
        Rem       ⑴程序假死,大概是死循环;显然是调整更新【解析】处出了问题,将其注释或删除如何?
        Rem       ⑵出现随机后的部分选枝残缺或混乱,显然又是定位出了问题。
        Rem  针对这些情况,请路过行家、大侠指教或搭手相助。
        
        .Pattern = "^\d+[\..][^\r]*[\((]([A-Z])[\))]\r(?:(?!(^\d+[\..]|^【解析】)).)+" '
        Rem .Pattern = "^\d+[\..][^\r]*[\((]([A-Z])[\))]\r(?:(?!(^\d+[\..])).)+"
        For Each mt In .Execute(str)
        
            sr1 = mt.submatches(0)
            m = mt.firstindex: n = mt.Length
            Set oRng = ActiveDocument.Range(m, m + n)
            
            fst = RegE.Execute(oRng)(0).firstindex
            lth = RegE.Execute(oRng)(0).Length
            Set rng1 = ActiveDocument.Range(oRng.Start + fst, oRng.Start + fst + lth)
            If Right(rng1.Text, 1) = vbCr Then rng1.End = rng1.End - 1
            
            Rem 下面.Pattern与上面.Pattern相配合使用,出现的问题同上。
            Rem .Pattern = "[A-Z]+[\..]((?!([A-Z][\..]|【解析】)).)+"
            .Pattern = "[A-Z]+[\..]((?![A-Z][\..]).)+"
            TT = Replace(oRng.Text, Chr(7), "")
            For Each mk In .Execute(TT)
                sr2 = Left(mk, 1)
                m = mk.firstindex: n = mk.Length
                Set rg = ActiveDocument.Range(oRng.Start + m, oRng.Start + m + n)
                rg.Start = rg.Start + 2: rg.End = rg.End - 1
                If Right(rg.Text, 1) = vbCr Then rg.End = rg.End - 1
                x = x + 1: k = k + 1: ReDim Preserve arr(1 To x)
                arr(x) = rg.Text: Set d(k) = rg
            Next
            
            If x > 0 Then '随机选枝
                ar = Rndcq(arr, x)
                For i = 0 To d.Count - 1
                    d.Items()(i).Text = ar(i + 1)
                Next
            End If
            
            DaId = Asc(Mid(rng1.Text, 2, 1)) - 64 '更新答案
            For i = 1 To UBound(ar)
              If ar(i) = arr(DaId) Then srr = Chr(64 + i): Exit For
            Next
            rng1.Text = "(" & srr & ")"
            
            For i = 1 To UBound(arr)
               For j = 1 To UBound(ar)
                 If ar(i) = arr(j) Then dic(Chr(i + 64)) = Chr(j + 64)
               Next
            Next
            ky = dic.Keys
            tm = dic.Items
            
            If RegX.test(TT) = True Then '调整更新【解析】中出现的A、B、C、D编号
            Rem 更新解析,运行到此处时,程序出现死循环,我自认为思路是不错的,可能是区域需要调整
            Rem 以前出现这个问题,此处保不定还是这个问题,可需要添加代码,由于学艺不精,不知所然。
            Rem 请大侠在此处多看看。
                ftdx = RegX.Execute(TT)(0).firstindex
                lgth = RegX.Execute(TT)(0).Length
                Set rng2 = ActiveDocument.Range(oRng.Start + ftdx, oRng.Start + ftdx + lgth)
                If Right(rng2.Text, 1) = vbCr Then rng2.End = rng2.End - 1
                With rng2.Find
                     For i = 0 To dic.Count - 1
                        Do While .Execute([A-Z], , , 1)
                            With .Parent
                                  If .Text = ky(i) Then .Text = tm(i)
                                 .Collapse
                            End With
                        Loop
                     Next
                End With
            End If
            
            x = 0: k = 0: d.RemoveAll: dic.RemoveAll
        Next
    End With
End Sub

Function Rndcq(arr, r As Integer)
    Dim arr1(), arr2%(), sr%, x%, y%, num%, k%
    k = UBound(arr)
    ReDim arr2(1 To k): ReDim arr1(1 To r)
    For y = 1 To k
        arr2(y) = y
    Next
    Randomize
    For x = 1 To r
        num = (Rnd() * ((k - x + 1) - 1) + 1) \ 1
        arr1(x) = arr(arr2(num))
        sr = arr2(num)
        arr2(num) = arr2(k - x + 1)
        arr2(k - x + 1) = sr
    Next x
    Rndcq = arr1
End Function

选枝随机、答案调整.rar

27.3 KB, 下载次数: 42

TA的精华主题

TA的得分主题

发表于 2020-4-12 23:24 来自手机 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
魏老师的功底不浅,能研懂并应用杜老师的代码实属不易,是我等小白学习的典范。

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-4-13 12:32 | 显示全部楼层
再次救助,希望大侠路过搭手相助。

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-4-13 18:34 | 显示全部楼层
本帖最后由 weiyingde 于 2020-4-13 19:41 编辑

自我检查,在下面的代码中添加了红色代码,仍没有理想结果。
                If Right(rng2.Text, 1) = vbCr Then rng2.End = rng2.End – 1
                Set myParRange = rng2.Paragraphs(1).Range.Duplicate
                With rng2.Find
                     For i = 0 To dic.Count - 1
                        Do While .Execute([A-Z], , , 1)
                            With .Parent
                                  If Not .InRange(myParRange) Then Exit Do
                                  If .Text = ky(i) Then .Text = tm(i)
仍然是死循环,不知为何……
潘大侠支招》》》》》

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-4-13 22:22 来自手机 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
再次求援,望高手赐教,谢谢

TA的精华主题

TA的得分主题

发表于 2020-4-14 00:27 | 显示全部楼层
可试试如下代码(对原文本有要求),较复杂,只作字符处理,代码较长。
  1. Option Explicit
  2. Dim answer As String
  3. Sub test()
  4.     Dim i As Integer
  5.     Dim oText As String
  6.     Dim regEx As Object
  7.     Dim Match As Object
  8.     Dim data() As String   '原数据
  9.     Dim data2() As Variant '随机重排后数据
  10.     Dim r As Variant
  11.     Dim oDoc As Document
  12.    
  13.     Set oDoc = ActiveDocument
  14.     oText = oDoc.Content.Text
  15.     Set regEx = CreateObject("vbscript.regexp")
  16.     With regEx
  17.         .Global = True:
  18.         .MultiLine = True
  19.         .Pattern = "(^\d+)([\..、][^\r]*[\((])([A-Z])([\))]\r)(([A-Z][\..、][^\r]*\r)*)(【解析】[^\r]+\r)"
  20.         For Each Match In .Execute(oText)
  21.             ReDim Preserve data(8, i)
  22.             data(0, i) = Match.Value
  23.             data(1, i) = Match.Submatches(0) '题号
  24.             data(2, i) = Match.Submatches(1) '
  25.             data(3, i) = Match.Submatches(2) '答案
  26.             data(4, i) = Match.Submatches(3)
  27.             data(5, i) = Match.Submatches(4) '选项,假设每个选项单独一段
  28.             data(6, i) = Match.Submatches(6) '解析,一个段落
  29.             data(7, i) = myOptions(data(3, i), data(5, i), Replace(data(6, i), Chr(13), "")) '重排后选项与解释
  30.             data(8, i) = answer '重排后答案
  31.             i = i + 1
  32.         Next
  33.     End With
  34.    
  35.     r = Randomizing(UBound(data, 2))
  36.     ReDim data2(UBound(r))
  37.     For i = 0 To UBound(r)
  38.         data2(i) = i + 1 & data(2, r(i)) & data(8, r(i)) & data(4, r(i)) & data(7, r(i))
  39.     Next
  40.    
  41.     Documents.Add.Content.Text = Join(data2, vbCrLf)
  42. End Sub

  43. Function Explain(k As Variant, t As String) As Variant
  44.     '处理解析文本。假设除选项字母外没有相同的单独选项字母
  45.     Dim i As Integer
  46.     Dim j As Integer
  47.     Dim regEx As Object
  48.     Dim Match As Object
  49.     Dim sb() As Long
  50.     Dim atext() As String
  51.    
  52.     Set regEx = CreateObject("vbscript.regexp")
  53.     With regEx
  54.         .Global = True:
  55.         .MultiLine = True
  56.         .Pattern = "(\b[A-Z]\b)([^A-Z\r]+)"
  57.         For Each Match In .Execute(t)
  58.             With Match
  59.                 For j = 0 To UBound(k)
  60.                     If Chr(j + 65) = .Submatches(0) Then
  61.                         t = Left(t, .FirstIndex - 1) & Replace(t, .Submatches(0), Chr(k(j) + 65), .FirstIndex, 1)
  62.                         ReDim Preserve sb(i)
  63.                         sb(i) = .FirstIndex
  64.                         Exit For
  65.                     End If
  66.                 Next
  67.             End With
  68.             i = i + 1
  69.         Next
  70.     End With
  71.     For i = 0 To UBound(sb)
  72.         ReDim Preserve atext(i)
  73.         If i <> UBound(sb) Then atext(i) = Mid(t, sb(i) + 1, sb(i + 1) - sb(i)) Else atext(i) = Mid(t, sb(i) + 1)
  74.     Next
  75.     WordBasic.SortArray atext
  76.     Explain = atext
  77. End Function

  78. Function Randomizing(n As Integer) As Variant
  79.     '题号与选项顺序随机调整
  80.     Dim c As Integer
  81.     Dim i As Integer
  82.     Dim d As Object
  83.    
  84.     Set d = CreateObject("Scripting.Dictionary")
  85.     Randomize
  86.     Do Until d.Count = n + 1
  87.         c = Int(Rnd * (n + 1))
  88.         d(c) = ""
  89.     Loop
  90.    
  91.     Randomizing = d.Keys
  92. End Function

  93. Function myOptions(mydata1 As String, mydata2 As String, mydata3 As String) As String
  94.     '选项与解析重排
  95.     Dim c As Integer
  96.     Dim i As Integer
  97.     Dim n As Integer
  98.     Dim d As Object
  99.     Dim regEx As Object
  100.     Dim t1() As String
  101.     Dim t2() As String
  102.     Dim k
  103.    
  104.     t1 = Split(mydata2, Chr(13))
  105.     n = UBound(t1) - 1
  106.     k = Randomizing(n)
  107.     answer = Chr(k(Asc(mydata1) - 65) + 65)
  108.     For i = 0 To UBound(k)
  109.         t1(i) = Chr(k(i) + 65) & Mid(t1(i), 2)
  110.     Next
  111.     ReDim Preserve t1(UBound(k))
  112.     WordBasic.SortArray t1
  113.    
  114.     t2 = Explain(k, mydata3)
  115.     myOptions = Join(t1, Chr(13)) & vbCrLf & "【解析】" & Join(t2, "")
  116. End Function
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2020-4-14 05:50 来自手机 | 显示全部楼层
楼主厉害了。。。

如果是我,一般都是专门把 题目内容 和选项 放一个表,然后固定数目,比如4个选项,乱序,可能方便点,再生成试卷。。。
SRC_20200414_054727.png

TA的精华主题

TA的得分主题

发表于 2020-4-14 10:48 | 显示全部楼层
zpy2 发表于 2020-4-14 05:50
楼主厉害了。。。

如果是我,一般都是专门把 题目内容 和选项 放一个表,然后固定数目,比如4个选项,乱 ...

是一个解决方案。



                                            莫愁前路无知己,天下谁人不识君!只道是:海内存知己,天涯若比邻!  

    TA的精华主题

    TA的得分主题

     楼主| 发表于 2020-4-14 11:37 | 显示全部楼层
    [广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
    sylun 发表于 2020-4-14 00:27
    可试试如下代码(对原文本有要求),较复杂,只作字符处理,代码较长。

    喜出望外,担心泥牛入海,谁想这么快就有结果了!太感谢你了。

    TA的精华主题

    TA的得分主题

     楼主| 发表于 2020-4-14 11:42 | 显示全部楼层
    sylun 发表于 2020-4-14 00:27
    可试试如下代码(对原文本有要求),较复杂,只作字符处理,代码较长。

    sylun大侠,另起炉灶,这下老牛又有草料了,我可能要反刍好几天了
    不过,今天我先测试,有问题,还要向你请教
    若是再麻烦你,请你忍耐!海涵!!帮助!!!
    再次谢谢你!!!
    您需要登录后才可以回帖 登录 | 免费注册

    本版积分规则

    手机版|关于我们|联系我们|ExcelHome

    GMT+8, 2024-11-28 04:46 , Processed in 0.058638 second(s), 11 queries , Gzip On, MemCache On.

    Powered by Discuz! X3.4

    © 1999-2023 Wooffice Inc.

    沪公网安备 31011702000001号 沪ICP备11019229号-2

    本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

    快速回复 返回顶部 返回列表