基于第二个分隔符后面的字符串对列表进行排序

时间:2014-11-05 05:34:25

标签: sorting batch-file

应该很容易,但经过多次搜索仍然无法得到它。我需要按照第二个斜杠后面的数字排序看起来像这样的列表:

 /1628907159142/20141024021655
 /01_B00I7VVZAI_G6/20141028100307 
 /1358737922754/20141013173229
 /1307314535151/20141023185621
 ...

这些是时间戳。前8个字符=日期。我需要最早的日期顺序列表。时间并不重要。输出看起来像这样:

 /1358737922754/20141013173229
 /1307314535151/20141023185621
 /1628907159142/20141024021655
 ...

我在这里误解了一些东西。我已尝试过以下几种排列,所有这些排列似乎都基于第一个标记排序。我使用过令牌= 2,令牌= 2 *,令牌= 1,2回显%% H %% G等等。只有dif是字符串的哪一部分进入文件。列表总是按照第一个斜杠后的数字排序。

FOR /f "tokens=2 delims=/" %%G IN ('sort ^<Input.txt') DO (
    ECHO %%G >>output.txt
)

我发现下面的内容是根据每行上一个空格后面的字符串对行进行排序。我只为我的案例修改了delims和var name。不知道为什么要添加和删除12个点,但是可以保留它。

setlocal enableextensions
    for /f "tokens=1,2 delims=/" %%a in (Input.txt) do (
    set "_date=............%%b"
    call set %%_date:~-12%%=%%a
    )
    for /f "tokens=1* delims==." %%a in ('set .') do >>output.txt echo %%b %%a

看起来它应该没有delayedexpansion,但它不适合我。而且我无法获得&#34;通话设置&#34;无论我如何使用!标记,都可以使用DelayedExpansion。谢谢。

2 个答案:

答案 0 :(得分:0)

您在提取令牌之前进行排序。内置排序不提供基于分隔符排序的方法,因此您必须在排序之前重新排列输入。尝试这样的事情:

del temp.txt output.txt
FOR /f "tokens=1-2 delims=/" %%G IN (Input.txt) DO (
    ECHO /%%H/%%G >>temp.txt
)
sort <temp.txt >temp2.txt
FOR /f "tokens=1-2 delims=/" %%G IN (temp2.txt) DO (
    ECHO /%%H/%%G >>output.txt
)
del temp.txt temp2.txt

答案 1 :(得分:0)

尝试使用环境变量对数据进行排序的非操作代码很容易修复:

@echo off
setlocal disableDelayedExpansion

:: Clear existing _ variables
for /f "delims==" %%A in ('set _ 2^>nul') do set "%%A="

:: Load the data into _ variables.
:: The date is in the name, and the full line is in the value.
:: A line number is included in name just in case two rows have the same date.
:: I use FINDSTR /N to establish the line numbers.
for /f "tokens=1* delims=:" %%A in ('findstr /n . "input.txt"') do (
  for /f "tokens=2 delims=/" %%C in ("%%B") do set "_%%C_%%A=%%B"
)

:: Sort and write result
:: The SET command automatically sorts variables by name
>output.txt (
  for /f "tokens=2 delims==" %%A in ('set _') do echo %%A
)

但是有一个更简单的解决方案: - )

我更新了JSort.bat utility,允许您从给定的令牌位置开始排序。

JSort.bat是一个混合JScript /批处理脚本,它提供比标准Windows SORT命令更多的功能。它是纯脚本,可​​以在任何Windows机器上从XP开始本地运行。完整的文档嵌入在脚本中。

JSort.bat比本机SORT命令慢得多,并且它的最大文件大小限制在10 MB左右。

假设JSort.bat位于当前目录中,或者更好,位于PATH中的某个位置,那么排序操作可以简单如下:

jsort input.txt /t 3 /d "/" >output.txt

请注意,我使用/ T 3,因为每行的开头都有一个空标记。

这是实际的JSort.bat脚本。我不保证在此网站上保持此代码的最新状态。当前版本始终可以在DosTips找到。

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

::************ Documentation ***********
::JSORT.BAT version 3.2
:::
:::JSORT [File] [/Option [Value]]...
:::
:::  Sort lines of text from stdin and write the result to stdout.
:::  JSORT uses an ascending, case sensitive text sort by default.
:::
:::    File - If the optional File argument is specified, then JSORT reads lines
:::           from the file instead of from stdin. If specified, the File must
:::           be the very first argument.
:::
:::  Options:
:::
:::    /C n - Number of sorted lines to print. Skipped lines are always printed
:::           and do not contribute to the count. Default is -1 (all lines).
:::
:::    /D String - Specifies the string used to delimit tokens. The delimiter
:::           string is always case sensitive. A quote literal " must be escaped
:::           as \q, and a backslash literal \ must be escaped as \\.
:::           The default value is an empty string, meaning treat the entire
:::           line as a single token.
:::
:::    /I   - Ignore case when sorting
:::
:::    /N   - Sort consecutive digits as numbers instead of text. The numbers
:::           may be embedded within alpha text. JSort supports numbers up to
:::           20 digits long.
:::
:::    /O File - Writes the output to File instead of stdout.
:::
:::    /P n - Begin sorting at character position n relative to the beginning
:::           of the selected token. Lines that do not extend that far are
:::           treated as equivalent values, and collate before all other lines.
:::           The default value is 1 (first character).
:::
:::    /R   - Sort the lines in Reverse (descending) order.
:::
:::    /S n - Number of lines to skip - default is 0.
:::           Skipped lines are not sorted (remain in place)
:::
:::    /T n - Specify the token at which to begin sorting. The default value
:::           is 1 (first token).
:::
:::    /V   - Display the version of JSORT.BAT.
:::
:::    /?   - Display this help
:::
:::JSORT.BAT was written by Dave Benham and originally posted at
:::http://www.dostips.com/forum/viewtopic.php?f=3&t=5595
:::

::************ Batch portion ***********
@echo off
setlocal disableDelayedExpansion

:: Get optional input file
set "infile="
set "test=%~1"
setlocal enableDelayedExpansion
if defined test if "!test:~0,1!" neq "/" (
  endlocal
  set ^"infile=^<"%~1""
  shift /1
) else endlocal

:: Define options
set "options= /?: /i: /c:-1 /n: /p:1 /r: /s:0 /v: /d:"" /t:1 /o:"" "

:: Set default option values
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"

:: Get options
:loop
if not "%~1"=="" (
  setlocal enableDelayedExpansion
  set "test=!options:* %~1:=! "
  if "!test!"=="!options! " (
      >&2 echo Error: Invalid option %~1
      exit /b 1
  ) else if "!test:~0,1!"==" " (
      endlocal
      set "%~1=1"
  ) else (
      endlocal
      set "%~1=%~2"
      shift /1
  )
  shift /1
  goto :loop
)

:: Display help
if defined /? (
  for /f "delims=: tokens=*" %%A in ('findstr "^:::" "%~f0"') do echo(%%A
  exit /b 0
)

:: Display version
if defined /v (
  for /f "delims=: tokens=*" %%A in ('findstr /bc:"::JSORT.BAT version" "%~f0"') do echo %%A
  exit /b 0
)

:: Transform and validate options
set /a "case=0%/i%, num=0%/n%, pos=%/p%-1, tok=%/t%-1, order=1-2*0%/r%, 1/!(0x80000000&pos), 1/!(0x80000000&tok)" 2>nul || (
  >&2 echo Error: Invalid option value.
  exit /b 1
)
set "outfile="
if defined /o set ^"outfile=^>"%/o%""

:: Perform the sort
%infile% %outfile% cscript //E:JScript //nologo "%~f0" %case% %num% %pos% %order% %/s% %/c% %tok% "%/d%"

exit /b 0
************* JScript portion **********/
var array=new Array(),
    nocase =WScript.Arguments.Item(0),
    numeric=WScript.Arguments.Item(1),
    pos    =WScript.Arguments.Item(2),
    order  =WScript.Arguments.Item(3),
    skip   =WScript.Arguments.Item(4),
    count  =WScript.Arguments.Item(5),
    token  =WScript.Arguments.Item(6),
    delim  =WScript.Arguments.Item(7).replace(/\\(?!q|\\)/g,'').replace(/\\\\/g,'\\s').replace(/\\q/g,'"').replace(/\\s/g,'\\');
while (!WScript.StdIn.AtEndOfStream) {
  if (skip > 0) {
    WScript.Echo(WScript.StdIn.ReadLine());
    skip-=1
  } else {
    var expanded="", num="", raw=WScript.StdIn.ReadLine(), upper=((nocase==1)?raw.toUpperCase():raw);
    for( var i=pos+FindToken(raw,delim,token); i<raw.length; i++ ) {
      var c=upper.substr(i,1);
      if (numeric==1 && c>="0" && c<="9") {
        num+=c;
      } else {
        if (num != "") {
          num="00000000000000000000" + num;
          expanded+=num.substr(num.length-20);
          num="";
        }
        expanded+=c;
      }
    }
    if (num != "") {
      num="00000000000000000000" + num;
      expanded+=num.substr(num.length-20);
    }
    var obj={expanded:expanded, raw:raw};
    array.push(obj);
  }
}
if (count<0) count=array.length;
if (count>array.length) count=array.length;
array.sort(function(a,b){return order*((a.expanded>b.expanded)-(a.expanded<b.expanded));});
for (var i=0; i<count; i++) WScript.Echo(array[i].raw);

function FindToken(str, str2, n) {
  if (n>0 && str2=="") return str.length;
  var rtn = 0;
  for( var i=n; i>0; i-- ) {
    rtn = str.indexOf(str2,rtn);
    if (rtn<0) return str.length;
    rtn+=str2.length;
  }
  return rtn;
}