VBScript - 如何按数值对文本文件中的字母数字字符串进行排序?

时间:2016-12-23 20:20:00

标签: sorting vbscript

我的数据如下:

9999.81GB increase - "c:\$RECYCLE.BIN"   1.91GB total
101.57GB increase - "c:\Windows"   101.61GB total
11.54GB increase - "c:\Program Files (x86)"   11.55GB total

我希望它看起来像这样:

Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile1 = objFSO.OpenTextFile("C:\Source.txt", ForReading)

Do Until objFile1.AtEndOfStream
FileContent = objFile1.ReadLine
arr1 = Split(FileContent,".",2)
arr2 = Array(arr1(0))

For i=0 to UBound(arr2)
WScript.Echo arr2(i)

Next
Loop

我一直试图对此进行冒泡。我假设我需要先在第一个"之前拆分字符串。"这将是一个可用于排序的数字。我用这样的方法管理了这个:

Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objOpen = objFSO.OpenTextFile("C:\Source.txt", ForReading)

Do Until objOpen.AtEndOfStream
FileContent = objOpen.ReadLine
arr1 = Split(FileContent,".",2)
arr2 = Array(arr1(0))

Do
x = UBound(arr2)
  y = -1
  For j = LBound(arr2) to x - 1
      If arr(j) > arr2(j + 1) Then
         TempValue = arr2(j + 1)
         arr2(j + 1) = arr2(j)
         arr2(j) = TempValue
         y = j
      End If
  Next
  x = y
Loop Until y = -1

z = ""
For i = UBound(arr2) To LBound(arr2)
    z = z & arr2(i) & "." & arr1(1) & vbCrlf

Next  
Loop
 WScript.echo z 

但是我不需要回声,而是需要在冒泡排序中使用这些值。这就是我似乎陷入困境的地方。

我打算使用不同类型的排序......但是永远不会有很多行要排序,所以我认为泡泡可能是一个不错的选择。

这是我能做的最好的事情:

{{1}}

但这只输出最后一行,它似乎甚至没有尝试排序。

我是新来的:)任何帮助将不胜感激。

亚瑟

3 个答案:

答案 0 :(得分:1)

我能够找到使用Tomalak领先的零点想法的解决方案。我无法使用.ReadAll工作。这是我做的:

Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile1 = objFSO.OpenTextFile("C:\Source.txt", ForReading)
Set objFile2 = objFSO.CreateTextFile("C:\Result.txt")
Do Until objFile1.AtEndOfStream
Line = objFile1.ReadLine
Split1 = Split(Line,".",2)
Split2 = Split1(0)

result = string(7 - Len(Split2), "0") & Line
objFile2.Write result & vbCrlf

Loop

从这里开始,我只使用Windows命令提示符排序。

我知道这可能不太理想..但是它有效!谢谢Tomalak!

如果你觉得无聊并希望向我展示更好的方法,请这样做。记住......我正在尝试学习,因为我走的是一个非常基本的水平...所以请轻松解释:)

亚瑟

答案 1 :(得分:0)

这使用记录集,可以在内存中创建,然后进行排序和过滤。它使用正则表达式来查找可能是数字或日期。 RegEx假设英语数字和日期,如果不是这样的话会改变。

它是大型程序的一部分,因此这里忽略了param1。

它使用重定向而不是打开和关闭文件。因此,它必须与CSCript一起运行。

$p

<强>排序

Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout

    Set rs = CreateObject("ADODB.Recordset")
    If LCase(Arg(1)) = "n" then
    With rs
        .Fields.Append "SortKey", 4 
        .Fields.Append "Txt", 201, 5000 
        .Open
        Do Until Inp.AtEndOfStream
            Lne = Inp.readline
            SortKey = Mid(Lne, LCase(Arg(3)), LCase(Arg(4)) - LCase(Arg(3)))
            If IsNumeric(Sortkey) = False then
                Set RE = new Regexp
                re.Pattern = "[^0-9\.,]"
                re.global = true
                re.ignorecase = true
                Sortkey = re.replace(Sortkey, "")
            End If
            If IsNumeric(Sortkey) = False then
                Sortkey = 0
            ElseIf Sortkey = "" then
                Sortkey = 0
            ElseIf IsNull(Sortkey) = true then
                Sortkey = 0
            End If
            .AddNew
            .Fields("SortKey").value = CSng(SortKey)
            .Fields("Txt").value = Lne
            .UpDate
        Loop
        If LCase(Arg(2)) = "a" then SortColumn = "SortKey ASC"
        If LCase(Arg(2)) = "d" then SortColumn = "SortKey DESC"
        .Sort = SortColumn
        Do While not .EOF
            Outp.writeline .Fields("Txt").Value
            .MoveNext
        Loop
    End With

    ElseIf LCase(Arg(1)) = "d" then
    With rs
        .Fields.Append "SortKey", 4 
        .Fields.Append "Txt", 201, 5000 
        .Open
        Do Until Inp.AtEndOfStream
            Lne = Inp.readline
            SortKey = Mid(Lne, LCase(Arg(3)), LCase(Arg(4)) - LCase(Arg(3)))
            If IsDate(Sortkey) = False then
                Set RE = new Regexp
                re.Pattern = "[^0-9\\\-:]"
                re.global = true
                re.ignorecase = true
                Sortkey = re.replace(Sortkey, "")
            End If
            If IsDate(Sortkey) = False then
                Sortkey = 0
            ElseIf Sortkey = "" then
                Sortkey = 0
            ElseIf IsNull(Sortkey) = true then
                Sortkey = 0
            End If
            .AddNew
            .Fields("SortKey").value = CDate(SortKey)
            .Fields("Txt").value = Lne
            .UpDate
        Loop
        If LCase(Arg(2)) = "a" then SortColumn = "SortKey ASC"
        If LCase(Arg(2)) = "d" then SortColumn = "SortKey DESC"
        .Sort = SortColumn
        Do While not .EOF
            Outp.writeline .Fields("Txt").Value
            .MoveNext
        Loop
    End With


    ElseIf LCase(Arg(1)) = "t" then
    With rs
        .Fields.Append "SortKey", 201, 260 
        .Fields.Append "Txt", 201, 5000 
        .Open
        Do Until Inp.AtEndOfStream
            Lne = Inp.readline
            SortKey = Mid(Lne, LCase(Arg(3)), LCase(Arg(4)) - LCase(Arg(3)))
            .AddNew
            .Fields("SortKey").value = SortKey
            .Fields("Txt").value = Lne
            .UpDate
        Loop
        If LCase(Arg(2)) = "a" then SortColumn = "SortKey ASC"
        If LCase(Arg(2)) = "d" then SortColumn = "SortKey DESC"
        .Sort = SortColumn
        Do While not .EOF
            Outp.writeline .Fields("Txt").Value
            .MoveNext
        Loop
    End With
    ElseIf LCase(Arg(1)) = "tt" then
    With rs
        .Fields.Append "SortKey", 201, 260 
        .Fields.Append "Txt", 201, 5000 
        .Open
        Do Until Inp.AtEndOfStream
            Lne = Inp.readline
            SortKey = Trim(Mid(Lne, LCase(Arg(3)), LCase(Arg(4)) - LCase(Arg(3))))
            .AddNew
            .Fields("SortKey").value = SortKey
            .Fields("Txt").value = Lne
            .UpDate
        Loop
        If LCase(Arg(2)) = "a" then SortColumn = "SortKey ASC"
        If LCase(Arg(2)) = "d" then SortColumn = "SortKey DESC"
        .Sort = SortColumn
        Do While not .EOF
            Outp.writeline .Fields("Txt").Value
            .MoveNext
        Loop
    End With
    End If

对文件进行排序

filter Sort {n|d|t|tt} {a|d} startcolumn  endcolumn

示例

n - extracts a number from the columns specified. Looks for the first number.
d - extracts a time or date from the columns specified. Looks for the first date.
t - extracts a text string including spaces from the columns specified.
tt - extracts a text string discarding leading and trailing spaces from the columns specified.

a - sorts acending
d - sorts decending

startcolumn - the starting column, the first character is column 1

endcolumn - the ending column

请参阅https://1drv.ms/f/s!AvqkaKIXzvDieQFjUcKneSZhDjw的filter.zip,其中包含VBS文本处理例程。

  • 通过常规表达式过滤文件

  • 使用常规表达式查找并替换文件中的文本。还从文件

  • 中提取子字符串
  • 过滤并选择上一行和下一行

使用VBScript表达式

  • 使用命令行中针对每行指定的文本运行vbscript

排序

  • 按数字,字母或按日期对文件进行排序

  • 随机化文件中的行以取消

  • 删除文件中的重复行

  • 反转行中的文字以进行反向搜索

  • 交换文件中的行顺序

空行和空格

  • 修剪文件顶部或底部的空白行

  • 修剪前导和尾随空格

  • 从文件中删除所有空白行

  • 修复行结尾

常规

  • 大声说出文字

  • 将HTML转换为文字

  • 从文件的顶部或底部删除或离开指定数量的行

  • 将StdIn写入文件和StdOut

  • 计算文件中的行并使用计数

  • 设置环境变量

剪贴板和网络服务器

过滤器也可以作为写入StdOut的源。

  • 将剪贴板的内容写入StdOut

  • 将指定网页的内容写入StdOut

答案 2 :(得分:0)

我读了几遍,在我看来,问题是&#34;为什么不排序?&#34;

&#34;但这只输出最后一行,它似乎甚至没有尝试排序。&#34;

答案很简单:您只是尝试从一行排序数据。以下是伪代码中算法的概述:

Read line by line (outer loop)
  extract the number and place it into arr2
  bubble sort algorithm on top of arr2 that contains data for 1 line only(inner loop) 
end outer loop

我到了我的Windows框,所以这里是VBScript中的一个工作版本。最复杂的部分是getSize()函数,因为它必须仔细解析字符串以提取大小。我也在大小单位转换中支持GB,MB和KB。

' -----------------------------------------------------------'
' the most complicated part: extracts size info form the string
Function getSize (line)
    kbSize = 0

    ' check that there is a data in the line
    if Len(line) <> 0 then
        arr = Split(line," ")
        ' extract the size and the unit of measurement
        size = Left(arr(0), Len(arr(0))-2)
        unit = UCase(Right(arr(0), 2))
        ' convert all sizes to KBs
        select case unit
            case "GB"
                kbSize = size * 1024 * 1024
            case "MB"
                kbSize = size * 1024
            case "KB"
                kbSize = size
            case else 
                Err.raise 101, "getSize", "do not recignize the size unit " + unit + " in the line " + line
        end select
    end if

    ' remember that the size is not integer
    getSize = CDbl(kbSize)
End Function

' -----------------------------------------------------------'
' your main program flow

Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile1 = objFSO.OpenTextFile("Source.txt", ForReading)

' slurp the whole file into memory
content = objFile1.ReadAll
'split file into arry line by line
lines = Split(content, vbCrLf)

' bubble sort lines to avoid brain strain
For i = LBound(lines) to UBound(lines)
  For j = i+1 to UBound(lines)
      If getSize(lines(i)) < getSize(lines(j)) Then
         TempValue = lines(i)
         lines(i) = lines(j)
         lines(j) = TempValue
      End If
  Next
Next

' get the sorted array and join it back into string for easy of output
output = Join(lines, vbCrLf)
WScript.echo output