1

一連のテキスト ファイル (字幕ファイル) の特定の行の最初と 2 番目のコンマの間にある文字列を抽出しようとしています。テキスト ファイルは次のようにフォーマットされます。

Subtitles01.txt

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour
Style: Default, Estrangelo Edessa, 57, &H00FFFFFF
Style: Title1, Arno Pro, 65, &H00606066

Subtitles02.txt

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour
Style: OP Eng, Arno Pro, 45, &H00100F11
Style: ED Romaji, Nueva Std Cond, 46, &H00FFFFFF

Subtitles03.txt

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour
Style: OP Eng, Estrangelo Edessa, 45, &H00100F11
Style: Default, Arno Pro, 45, &H00100F11
Style: ED Romaji, Nueva Std Cond, 46, &H00FFFFFF

ここで達成したいのは、「Style:」で始まる各行の Fontname を抽出し、必要なフォントがどの字幕に含まれているかを繰り返さない方法で判別することです。したがって、基本的に、最終結果は次のようなテキストファイルに出力されます。

Subtitles01.txt: Estrangelo Edessa
Subtitles01.txt: Arno Pro
Subtitles02.txt: Arno Pro
Subtitles02.txt: Nueva Std Cond
Subtitles03.txt: Estrangelo Edessa
Subtitles03.txt: Arno Pro
Subtitles03.txt: Nueva Std Cond

Only Subtitles03.txt is needed.

Subtitles03.txt には Subtitles01.txt と Subtitles02.txt のすべてのフォントが含まれているため、Subtitles03.txt のみが必要です。目標は、最小限のファイルを使用して、すべてのファイルで一意のフォントを見つけることです。「Style:」で始まる行を抽出するためにfindstrを使用して次のバッチ スクリプトを作成しましたが、それ以上は行き詰っています。

@echo off
findstr /B /C:"Style:" *.txt > results.txt
if %errorlevel%==0 (
    echo Found! logged files into results.txt
) else (
    echo No matches found
)

どんな助けでも大歓迎です。君たちありがとう!

4

5 に答える 5

1

編集:これを使用してください:

^Style:\s*([^,]+)\s*,\s*([^,]+)\s*,\s*([^,]+)\s*,\s*(.+)\s*
于 2012-07-09T07:40:02.550 に答える
1

バッチ以外の言語を使用するか、少なくとも非ネイティブのユーティリティを使用する方がはるかに簡単だと思います。しかし、これは純粋なネイティブバッチソリューションです。

FINDSTR正規表現がこの問題にどのように役立つかわかりません。他の多くの非ネイティブバッチ正規表現ユーティリティのように、一致する行の一部を抽出することはできません。

FOR / Fを使用して、各ファイルからフォントを抽出できます。

for /f "tokens=2 delims=," %%A in ('findstr /lb "Style:" file.txt') do echo font=%%A

環境変数を使用して、固有のフォントのリストを作成できます。変数名にフォント名を付けて変数を定義します。すべて接頭辞はfont_。です。特定の名前に定義できる変数は1つだけです。割り当てられた値は重要ではありません。次に、を使用set font_して、すべての一意のフォント名を一覧表示できます。一意の名前の数を数えるか、実際のフォント名を解析することができます(font_プレフィックスを削除します)。

トリッキーな部分は、一意のフォント名の完全なセットをカバーするために必要なファイルの最小セットを確立することです。誰かが効率的な解決策を思い付くことができると思います。ブルートフォース再帰順列法を採用しました。各順列で見つかった一意のフォントの数を数え、その数を一意のフォントの総数と比較します。現在のセットよりも小さい完全なセットをすでに見つけた場合に、特定の順列パスを進まないようにするためのショートカットをいくつか追加しました。

再帰でSETLOCALを使用した場合、コードはより単純になる可能性がありますが、バッチはSETLOCALの32レベルのみに制限されています。32を超えるファイルをサポートできるソリューションが必要でしたが、その数のファイルでのパフォーマンスが少し心配です。

編集 -3つ以上のファイルがあると表面化するルーチンのバグを修正しました:permuteFiles

@echo off
setlocal enableDelayedExpansion

::Make sure there are no font_ variables defined
for /f "delims==" %%A in ('set font_ 2^>nul') do set "%%A="

::Read all the Subtitle files and
:: - create an "array" of file names
:: - create a file of font names for each input file
:: - create an "associative array" of unique font names
:: - List the available file/font pairs in the final results
:: - List the unique fonts in the final results
set fileCount=0
>results.txt (
  echo Available fonts
  echo ----------------------------
  for %%F in (subtitles*.txt) do (
    set /a totalFiles+=1
    set "file_!totalFiles!=%%F"
    3>"%%F.fonts" (
      for /f "tokens=2 delims=," %%A in ('findstr /lb "Style:" "%%F"') do (
        set "font_%%A=1"
        >&3 echo %%A
        echo %%F:%%A
      )
    )
  )
  echo(
  echo Unique fonts
  echo ----------------------------
  for /f "delims==" %%A in ('set font_') do (
    set "font=%%A"
    echo !font:~5!
  )
)

::Count the number of unique fonts
for /f %%N in ('set font_ ^| find /c /v ""') do set uniqueFonts=%%N

::Test all the permutations
set /a minFileCount=%totalFiles%+1
for /l %%N in (1 1 %totalFiles%) do (
  call :permuteFiles %%N 0 ""
)

::List the required files in the final results
>>results.txt (
  echo(
  echo The following files contain the complete set of unique fonts:
  echo -------------------------------------------------------------
  for %%N in (%minFileList:~1,-1%) do echo !file_%%N!
)
type results.txt

::Cleanup
del subtitles*.txt.fonts
exit /b


:permuteFiles  fileNumber  fileCount  fileList
if %1==%totalFiles% (
  if %2 gtr 0 call :testPermutation %2 %3
  set /a fileCount=%2+1
  if !fileCount! lss !minFileCount! call :testPermutation !fileCount! "%~3,%1"
) else (
  set /a nextFile=%1+1
  if %2 gtr 0 call :permuteFiles !nextFile! %2 %3
  set /a "nextFile=%1+1, fileCount=%2+1"
  if !fileCount! lss !minFileCount! call :permuteFiles !nextFile! !fileCount! "%~3,%1"
)
exit /b


:testPermutation  fileCount  fileList
for /f "delims==" %%A in ('set font_ 2^>nul') do set "%%A="
for %%N in (%~2) do (
  for /f "usebackq delims=" %%A in ("!file_%%N!.fonts") do set "font_%%A=1"
)
for /f %%N in ('set font_ ^| find /c /v ""') do if %%N==%uniqueFonts% (
  set minFileList=%2
  set minFileCount=%1
)
exit /b

入力例を使用した結果は次のとおりです。

Available fonts
----------------------------
Subtitles01.txt: Estrangelo Edessa
Subtitles01.txt: Arno Pro
Subtitles02.txt: Arno Pro
Subtitles02.txt: Nueva Std Cond
subtitles03.txt: Estrangelo Edessa
subtitles03.txt: Arno Pro
subtitles03.txt: Nueva Std Cond

Unique fonts
----------------------------
 Arno Pro
 Estrangelo Edessa
 Nueva Std Cond

The following files contain the complete set of unique fonts:
-------------------------------------------------------------
subtitles03.txt
于 2012-07-09T23:46:24.660 に答える
1

「目標は、すべてのファイルで一意のフォントを見つけるために最小限のファイルを使用することです」場合、以下のバッチファイルが問題を解決します。

編集:オプス!以前のコードに小さなバグがありました。ターゲット ファイルに含まれる各フォント名を処理するときにファイル全体を削除するべきではなく、そのフォント名をファイル数から差し引くだけです。以下のコードのバグを修正しました (実際、今ではより簡単です)。

@echo off
setlocal EnableDelayedExpansion

rem Create "Files with Fontnames" and "Fontnames in Files" sets, 
rem and FileCount with number of Fontnames in each file
for %%a in (*.txt) do (
   for /F "tokens=2 delims=," %%b in ('findstr /B /C:"Style:" %%a') do (
      set File[%%~Na]=!File[%%~Na]!"%%b",
      set Fontname[%%b]=!Fontname[%%b]!%%~Na,
      set /A FileCount[%%~Na]+=1
   )
)

echo Fonts by File:
set File[
echo/
echo/

echo Following files provide all fonts:

rem For each non-processed "File with Fontnames"
:nextFile

   rem Process File with larger number of Fontnames first
   set fontCount=0
   for /F "tokens=2,3 delims=[]=" %%a in ('set FileCount[') do (
      if %%b gtr !fontcount! (
         set fontCount=%%b
         set nextFile=%%a
      )
   )
   if %fontCount% equ 0 goto exit

   rem Show this file as result
   echo File %nextFile%.txt

   rem For each Fontname in this file
   for %%a in (!File[%nextFile%]!) do (
      rem Subtract this Fontname from the Files that include it
      for %%b in (!Fontname[%%~a]!) do (
         set /A FileCount[%%b]-=1
      rem and delete this Fontname
      set Fontname[%%~a]=
      )
   )

rem Go back to process next file
goto nextFile

:exit

例えば:

Fonts by File:
File[Subtitles01]=" Estrangelo Edessa"," Arno Pro",
File[Subtitles02]=" Arno Pro"," Nueva Std Cond",
File[Subtitles03]=" Estrangelo Edessa"," Arno Pro"," Nueva Std Cond",


Following files provide all fonts:
File Subtitles03.txt
于 2012-07-10T00:51:36.990 に答える
1

Perl がデフォルトでインストールされていない、または Perl がインストールされていないプラットフォームを使用しているawkようですが、特に将来同様のタスクを実行する必要がある場合は、これらのツールのいずれかをインストールすることを検討することをお勧めします。

awk -F, '/^Style:/ { print FILENAME ":" $2 }' *.txt

または Perl の場合:

perl -ne 'print "$ARGV:$1\n" if m/^Style: [^,]*,([^,]*)/' *.txt

その後の最適化 (他の一致するファイルと重複するファイルを削除する) は、どちらの言語でも難しくありません。Perl は、より大きく多様なタスクにうまく対応できるため、両方に慣れていない場合は、Perl を最初にお勧めします (ただし、学習曲線が長くなり、多少でこぼこになりますので、Python も検討する必要があります)。

于 2012-07-09T08:33:26.327 に答える
0
Style: (.*),(.*),(.*),(.*)

次に、2 番目に一致した結果を取得します。文字列全体を使用していることを確認してください。かっこから始めるだけではありません。

編集

申し訳ありませんが、実際には 3 つのブロックと 2 つのコンマではなく、3 つのコンマで 4 つのブロックがあったことを見逃していました。コードは現在機能しており、修正されています。

于 2012-07-09T07:26:03.380 に答える