Пакетное создание папок на основе части имени файла без сохранения расширения

Стандарт был изменен, так как вопрос (и большинство ответов) был опубликован в разрешении этого отчета о дефектах .

Способ создания работы for(:) на вашем типе X теперь является одним из двух способов:

  • Создать участника X::begin() и X::end(), которые возвращают что-то, что действует как итератор
  • Создать бесплатный функции begin(X&) и end(X&), которые возвращают то, что действует как итератор, в том же пространстве имен, что и ваш тип X

И аналогично для const вариантов. Это будет работать как на компиляторах, реализующих изменения отчета об ошибках, так и на компиляторах, которые этого не делают.

Возвращаемые объекты не обязательно должны быть итераторами. Контур for(:), в отличие от большинства частей стандарта C ++, указан в для расширения до эквивалента :

for( range_declaration : range_expression )

становится:

{
  auto && __range = range_expression ;
  for (auto __begin = begin_expr,
            __end = end_expr;
            __begin != __end; ++__begin) {
    range_declaration = *__begin;
    loop_statement
  }
}

, где переменные, начинающиеся с __, предназначены только для изложения, а begin_expr и end_expr - это магия, которая вызывает begin / end

Требования к началу / end return value: вы должны перегрузить pre- ++, убедитесь, что выражения инициализации верны, binary !=, которые могут использоваться в булевом контексте, унарные *, которые возвращают что-то, что вы можете назначить-initialize range_declaration с, и выставлять публичный деструктор.

Выполнение этого способом, который несовместим с итератором, вероятно, является плохой идеей, так как будущие итерации C ++ могут быть относительно бесцеремонными по поводу нарушения вашего кода, если вы это сделаете .

В стороне, вполне вероятно, что будущий пересмотр стандарта позволит end_expr вернуть другой тип, чем begin_expr. Это полезно в том смысле, что он позволяет оценивать «ленивый конец» (например, обнаружение нулевого окончания), который легко оптимизировать, чтобы быть таким же эффективным, как рукописный цикл C, и другие подобные преимущества.


¹ Обратите внимание, что петли for(:) сохраняют любое временное значение в переменной auto&& и передают его вам как lvalue. Вы не можете определить, выполняете ли вы повторное использование временного (или другого значения rvalue); такая перегрузка не будет вызываться контуром for(:). См. [Stmt.ranged] 1.2-1.3 из n4527.

² Либо вызовите метод begin / end, либо только поиск в режиме ADL свободной функции begin / end, или для поддержки массива в стиле C. Обратите внимание, что std::begin не вызывается, если range_expression не возвращает объект типа в namespace std или не зависит от него.


В диапазон - для выражения было обновлено

{
  auto && __range = range_expression ;
  auto __begin = begin_expr;
  auto __end = end_expr
  for (;__begin != __end; ++__begin) {
    range_declaration = *__begin;
    loop_statement
  }
}

с типами __begin и __end. Разделились.

Это позволяет конечному итератору не быть тем же типом, что и начать. Тип конечного итератора может быть «дозорным», который поддерживает только != с началом типа итератора.

Практическим примером того, почему это полезно, является то, что ваш конечный итератор может читать «проверьте ваш char* чтобы увидеть, указывает ли он на '0' «когда == с char*. Это позволяет выражению C ++ range-for генерировать оптимальный код при итерации над буфером char* с нулевым завершением.

struct null_sentinal_t {
  template{},int> =0
  >
  friend bool operator==(Rhs const& ptr, null_sentinal_t) {
    return !*ptr;
  }
  template{},int> =0
  >
  friend bool operator!=(Rhs const& ptr, null_sentinal_t) {
    return !(ptr==null_sentinal_t{});
  }
  template{},int> =0
  >
  friend bool operator==(null_sentinal_t, Lhs const& ptr) {
    return !*ptr;
  }
  template{},int> =0
  >
  friend bool operator!=(null_sentinal_t, Lhs const& ptr) {
    return !(null_sentinal_t{}==ptr);
  }
  friend bool operator==(null_sentinal_t, null_sentinal_t) {
    return true;
  }
  friend bool operator!=(null_sentinal_t, null_sentinal_t) {
    return false;
  }
};

live example в компиляторе без полного C + +17 поддержка; for цикл вручную расширен.

0
задан Gerhard Barnard 17 January 2019 в 12:48
поделиться

3 ответа

Вот альтернатива, которая будет просто использовать последнюю строку / число, разделенную пробелом, независимо от того, сколько их, (если их нет, будет использоваться полное имя файла) !

[110 ]

И если вы хотите переместить только те из них, которые имеют хотя бы один пробел, вы можете включить это в For скобки.

@Echo Off
For %%A In ("D:\Sourcedir\* *.pdf") Do Call :L "%%A"
Exit /B

:L
Set "F=%~n1"
Set "F=%F: ="&Set "F=%"
If Not Exist "%~dp1%F%\" MD "%~dp1%F%"
Move /Y %1 "%~dp1%F%"
0
ответ дан Compo 17 January 2019 в 12:48
поделиться

Почему вы использовали delims=? Это удалит разделитель и приведет целую строку к %%a.
Попробуйте это:

@ECHO OFF
SETLOCAL
SET "sourcedir=D:\Sourcedir"
PUSHD %sourcedir%
FOR /f "tokens=1,2,3" %%a IN (
 'dir /b /a-d "*.pdf"'
 ) DO (  
 ECHO MD %%~nc
 ECHO MOVE "%%a %%b %%c" .\%%~nc\
)
POPD

GOTO :EOF

Если не установлено delims=, будет использоваться пробел. Таким образом, %%c будет 10.pdf, ~n - извлечь его n часть.

Это основано на вашем вопросе, который вы можете объединить %%a %%b %%c вместе с spaces, тогда все просто.
Если ваши имена файлов более сложные, то лучше использовать внутренний цикл for.
- Какой другой вопрос уже дал отличное решение.

0
ответ дан Tiw 17 January 2019 в 12:48
поделиться

Вы можете запустить цикл 2 для получения полного имени в первом цикле, затем разделить имя во втором цикле, получить третий токен, создать каталог и затем скопировать фактическое имя файла из первого цикла.

Таким образом, вам не нужно снова пытаться соединить имя, я знаю, что это работает, но это некрасиво и не является предпочтительным:

@echo off
setlocal enabledelayedexpansion
set "sourcedir=D:\Sourcedir"
pushd %sourcedir%
for %%a in (*.pdf) do (
    set "var=%%a"
   for /f "tokens=3" %%i in ("!var!") do (
     echo md "%%~ni"
     echo move "%%~a" "%%~ni"
  )
)
popd
goto EOF

Для получения дополнительной информации об этих командах см. каждый из cmd.exe, т. е.

,
for /?
set /?
setlocal /?
,

, set и setlocal содержит очень конкретную информацию о задержке расширения.

0
ответ дан Gerhard Barnard 17 January 2019 в 12:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: