5

次の4行のファイルがあります。

A;1;abc;<xml/>;
;2;def;<xml
>hello world</xml>;
;3;ghi;<xml/>;

バッチファイルを使用して、行がセミコロン(;)で終わっていない場合は、次の行を現在の行に結合するように行を結合する必要があります。

したがって、目的の出力は次のようになります。

A;1;abc;<xml/>;
;2;def;<xml>hello world</xml>;
;3;ghi;<xml/>;

私はバッチスクリプトにあまり精通していませんが、使用してみましfor /Fたが、今のところ運がありません。

私が理解しているように、ロジックは各行の最後の文字をチェックする必要があります。セミコロンでない場合は、次の行を現在の行に読み込みます。

これに加えて、行の最後の文字を取得することができましたが、スクリプトは行が含まれていない場合にのみ行を読み取ります。。何か案は?

@echo off
for /f "tokens=*" %%i in (myfile.txt) do (
  set var=%%i
  echo %%i
  if "%var:~-1%"==";" (
    echo test
  )
)

注:上記のクエリは1行目と3行目のみを読み取ります。

4

3 に答える 3

7

あなたはあなたのコードに多くの問題を抱えています:)

1)あなたが述べたように、あなたのコードはで始まる行を無視します;-これはデフォルトのFOR /FEOLオプションによるものです。ただし、「TOKENS = *」が原因で、コードは各行の先頭のスペースも削除します。EOLとDELIMSの両方を何にも設定する必要はありません。構文は奇妙ですが、機能します。

for /f delims^=^ eol^= %%i ...

2)括弧で囲まれたコードブロック内でvarを設定および展開しようとしました。行が解析されるときに展開が発生し、コードのブロック全体が一度に解析されるため、これは機能しません。したがって、の値は%var%、ループが実行される前に存在していた値です。もちろん、あなたが望むものではありません。解決策は、遅延拡張を使用することです。FOR /?遅延拡張の詳細については、コマンドプロンプトから入力してください(ヘルプリストの約半分)

!3)遅延拡張が有効になっているときに拡張されると、含む可変コンテンツが破損します。解決策は、ループ内で必要に応じて遅延拡張のオンとオフを切り替えることです。しかし、ENDLOCALバリアを越えて成長するラインの値を維持する必要があるため、これは複雑さを引き起こします。FOR / Fを使用して、バリアを越えて値を転送します。

これがその仕事をするべき完全なバッチスクリプトです。最大長の〜8191バイトを超える行を処理できないという制限があります。

このコードは、重大なバグを修正するために書き直されました

@echo off
setlocal disableDelayedExpansion
set "ln="
set "print=0"
for /f delims^=^ eol^= %%i in (myfile.txt) do (
  set "var=%%i"
  setlocal enableDelayedExpansion
  for /f delims^=^ eol^= %%A in ("!ln!!var!") do (
    if "!var:~-1!"==";" (
      endlocal
      echo %%A
      set "ln="
    ) else (
      endlocal
      set "ln=%%A"
    )
  )
)

SET/Pソリューション

ENDLOCALを介して変数を転送することを心配する必要がないように、各行をすぐに出力するはるかに簡単なソリューションがあります。で終わらない行は、;SET/Pを使用して改行なしで印刷されます。

このソリューションには、次の制限があります。

1)SET / Pを介して印刷された行では、先頭のスペースが削除されます。この制限は、Vista以降のバージョンのWindowsにのみ適用されます。XPでは問題ありません。

2)David Ruhmannのおかげで、行が。で始まる場合、SET/Pが失敗することがわかりました=。非常に残念です:(

@echo off
setlocal disableDelayedExpansion
set "ln="
for /f delims^=^ eol^= %%i in (myfile.txt) do (
  set "var=%%i"
  setlocal enableDelayedExpansion
  if "!var:~-1!"==";" (echo !var!) else (<nul set /p ="!var!")
  endlocal
)

ハイブリッドバッチ/JScript正規表現ソリューション(防弾?)

簡単な正規表現検索とファイル内容の置換を可能にするハイブリッドバッチ/JScriptREPL.BATユーティリティを作成しました。それは仕事を本当に簡単にします。

次のコマンドは、制限なしですべての入力で機能するはずです。WindowsとUnixの両方のスタイルラインをサポートするように更新されました。そして、それは純粋なバッチソリューションよりもはるかに高速です。

findstr "^." myfile.txt|repl "([^;\r])\r?\n" "$1" m >"outFile.txt"

これがREPL.BATユーティリティです。完全なドキュメントがスクリプトに埋め込まれています。

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

::************ Documentation ***********
:::
:::REPL  Search  Replace  [Options  [SourceVar]]
:::REPL  /?
:::
:::  Performs a global search and replace operation on each line of input from
:::  stdin and prints the result to stdout.
:::
:::  Each parameter may be optionally enclosed by double quotes. The double
:::  quotes are not considered part of the argument. The quotes are required
:::  if the parameter contains a batch token delimiter like space, tab, comma,
:::  semicolon. The quotes should also be used if the argument contains a
:::  batch special character like &, |, etc. so that the special character
:::  does not need to be escaped with ^.
:::
:::  If called with a single argument of /? then prints help documentation
:::  to stdout.
:::
:::  Search  - By default this is a case sensitive JScript (ECMA) regular
:::            expression expressed as a string.
:::
:::            JScript syntax documentation is available at
:::            http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
:::  Replace - By default this is the string to be used as a replacement for
:::            each found search expression. Full support is provided for
:::            substituion patterns available to the JScript replace method.
:::            A $ literal can be escaped as $$. An empty replacement string
:::            must be represented as "".
:::
:::            Replace substitution pattern syntax is documented at
:::            http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
:::  Options - An optional string of characters used to alter the behavior
:::            of REPL. The option characters are case insensitive, and may
:::            appear in any order.
:::
:::            I - Makes the search case-insensitive.
:::
:::            L - The Search is treated as a string literal instead of a
:::                regular expression. Also, all $ found in Replace are
:::                treated as $ literals.
:::
:::            E - Search and Replace represent the name of environment
:::                variables that contain the respective values. An undefined
:::                variable is treated as an empty string.
:::
:::            M - Multi-line mode. The entire contents of stdin is read and
:::                processed in one pass instead of line by line. ^ anchors
:::                the beginning of a line and $ anchors the end of a line.
:::
:::            X - Enables extended substitution pattern syntax with support
:::                for the following escape sequences:
:::
:::                \\     -  Backslash
:::                \b     -  Backspace
:::                \f     -  Formfeed
:::                \n     -  Newline
:::                \r     -  Carriage Return
:::                \t     -  Horizontal Tab
:::                \v     -  Vertical Tab
:::                \xnn   -  Ascii (Latin 1) character expressed as 2 hex digits
:::                \unnnn -  Unicode character expressed as 4 hex digits
:::
:::                Escape sequences are supported even when the L option is used.
:::
:::            S - The source is read from an environment variable instead of
:::                from stdin. The name of the source environment variable is
:::                specified in the next argument after the option string.
:::

::************ Batch portion ***********
@echo off
if .%2 equ . (
  if "%~1" equ "/?" (
    findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" ""
    exit /b 0
  ) else (
    call :err "Insufficient arguments"
    exit /b 1
  )
)
echo(%~3|findstr /i "[^SMILEX]" >nul && (
  call :err "Invalid option(s)"
  exit /b 1
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0

:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b

************* JScript portion **********/
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) {
  options+=args.Item(2).toLowerCase();
}
var multi=(options.indexOf("m")>=0);
var srcVar=(options.indexOf("s")>=0);
if (srcVar) {
  options=options.replace(/s/g,"");
}
if (options.indexOf("e")>=0) {
  options=options.replace(/e/g,"");
  search=env(search);
  replace=env(replace);
}
if (options.indexOf("l")>=0) {
  options=options.replace(/l/g,"");
  search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
  replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("x")>=0) {
  options=options.replace(/x/g,"");
  replace=replace.replace(/\\\\/g,"\\B");
  replace=replace.replace(/\\b/g,"\b");
  replace=replace.replace(/\\f/g,"\f");
  replace=replace.replace(/\\n/g,"\n");
  replace=replace.replace(/\\r/g,"\r");
  replace=replace.replace(/\\t/g,"\t");
  replace=replace.replace(/\\v/g,"\v");
  replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
    function($0,$1,$2){
      return String.fromCharCode(parseInt("0x"+$0.substring(2)));
    }
  );
  replace=replace.replace(/\\B/g,"\\");
}
var search=new RegExp(search,options);

if (srcVar) {
  WScript.Stdout.Write(env(args.Item(3)).replace(search,replace));
} else {
  while (!WScript.StdIn.AtEndOfStream) {
    if (multi) {
      WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace));
    } else {
      WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace));
    }
  }
}
于 2013-01-11T13:58:14.820 に答える
4

遅延拡張なし

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /f "tokens=* eol=" %%L in (myfile.txt) do (
    <nul set /p ="%%L" 2>nul                         %= Fixed Limitation 3 =%
    set "xLine=%%L"
    call set "xLine=%%xLine:"=%%"                    %= Fix for Limitation 2 =%
    call :NewLine
)
endlocal
pause >nul
goto :eof

:NewLine
if "%xLine:~-1%"==";" echo.
goto :eof

遅延拡張あり

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /f "tokens=* eol=" %%L in (myfile.txt) do (
    <nul set /p ="%%L" 2>nul                         %= Fixed Limitation 3 =%
    setlocal EnableDelayedExpansion
    set "xLine=%%L"
    set "xLine=!xLine:"=!"                           %= Fix for Limitation 2 =%
    if "!xLine:~-1!"==";" echo.
    endlocal
)
endlocal
pause >nul

制限事項:(両方のバージョンで同じ)

  1. コマンドが原因で、行がequals =文字で始まらない場合があります<nul set /p "=%%L"
  2. コマンドが原因で、行が二重引用符「」文字で終わらない場合がありif "<var>"==";" echo.ます。
  3. 行頭の二重引用符"<nul set /p "=%%L"文字は、コマンドのために失われます。(dbenhamによって解決されました)
  4. オプションにより、行頭のスペースはトリミングされ"tokens=* eol="ます。delims^=^ eol^=コマンドによるオプションを使用したWindowsVista以降でも、同じ問題が発生しますset /ptokens私は、Windowsのすべてのバージョンで一貫性を保つための方法を実装することを選択しました。
  5. バッチラインの長さの制限。8191バイト。xpバッチファイルの行の長さの制限を参照してください。およびhttp://support.microsoft.com/kb/830473

注:これらの制限はいずれもスクリプトをクラッシュさせませんが、代わりに1と3を使用するとこれらの行がスキップされ、4を使用すると行の先頭のスペースが削除されます。

アップデート

コマンド=によって引き起こされる等式およびスペーストリミングの問題の(表示のみ!)解決策を見つけました。set /pただし、非表示文字をバッチスクリプトに入力する必要があります。これは、スクリプトの16進データを編集して行う必要があります。スペース以外の問題のない文字(で示されている.)の後にバックスペース文字(で示されている0x08)を配置すると、の値のみ%Var%が表示されます。 注:表示されていない文字もファイルに出力されるため、これはファイル出力の解決策としては機能しません。

set /p =".0x08%Var%"

このequalsの問題の理由は、setコマンドに変数名の解析に問題があり、変数名にequalsを含めることができないためです。

SETコマンドでは、変数名に等号を含めることはできません。

この問題は常に存在していましたが、Vista+で追加された主要なスペーストリミングの問題によって悪化しています。良い分析:http ://www.dostips.com/forum/viewtopic.php?f = 3&t = 4209

于 2013-01-11T16:23:40.277 に答える
0

set /Pこれはいくつかの制限を導入するため、コマンドを使用しないソリューションを次に示します。ここでは、該当する行が変数に連結され、末尾のセミコロンが検出されるとすぐに出力されますecho。これには、そのような制限はありません。コードには説明文が含まれています。

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "FILE=%~1" & rem // (input file from command line argument)
set "CHAR=;"   & rem // (character that marks the end of line)

rem // Initialise variables:
set "PREV=" & rem // (variable to collect lines to combine)
rem // Iterate through the lines of the given file:
for /F usebackq^ delims^=^ eol^= %%L in ("%FILE%") do (
    set "LINE=%%L"
    rem // Toggle delayed expansion to not lose `!` in text:
    setlocal EnableDelayedExpansion
    rem // Check last character of current line:
    if "!LINE:~-1!"=="%CHAR%" (
        rem /* Last character marks end of line, so output
        rem    collected previous lines and current one: */
        echo !PREV!!LINE!
        rem // Clear Cached previous lines:
        endlocal
        set "PREV="
    ) else (
        rem /* Last character does not mark end of line, so
        rem    do not output it but cache it in a variable;
        rem    the `for /F` loop lets the data pass `endlocal`: */
        for /F delims^=^ eol^= %%K in ("!PREV!!LINE!") do (
            endlocal
            set "PREV=%%K"
        )
    )
)
rem /* Output all remaining cached data in case the last line
rem    is not terminated by an end-of-line marker: */
if defined PREV (
    setlocal EnableDelayedExpansion
    echo !PREV!
    endlocal
)

endlocal
exit /B
于 2016-09-03T01:04:19.227 に答える