Вы не предоставили достаточно большой сэмпл из вашего входного файла. Но, по сути, вам нужно сначала разделить содержимое файла по разделителю ;
. Затем для каждого полученного вами номера строки замените все разделители тысяч .
на «» (ничего). Затем замените десятичный символ ,
нормальным десятичным обозначением .
. Вот попытка добиться этого с помощью splitStr()
и replaceStr()
процедур с привязкой к типу, приведенных ниже, протестированных в строке содержания файла примера, которую вы предоставили 5;56,67;123.456,78
module String_mod
use, intrinsic :: iso_fortran_env, only: IK=>int32, RK=>real64
implicit none
public
character(*), parameter :: MODULE_NAME = "@String_mod"
type :: CharVec_type
character (:), allocatable :: record
end type CharVec_type
type :: String_type
character(:) , allocatable :: value
type(CharVec_type), allocatable :: Parts(:)
integer(IK) :: nPart = 0
contains
procedure, nopass :: replaceStr, splitStr, str2num
end type String_type
!***********************************************************************************************************************************
!***********************************************************************************************************************************
contains
!***********************************************************************************************************************************
!***********************************************************************************************************************************
recursive function replaceStr(string,search,substitute) result(modifiedString)
implicit none
character(len=*), intent(in) :: string, search, substitute
character(len=:), allocatable :: modifiedString
integer(IK) :: i, stringLen, searchLen
stringLen = len(string)
searchLen = len(search)
if (stringLen==0 .or. searchLen==0) then
modifiedString = ""
return
elseif (stringLen<searchLen) then
modifiedString = string
return
end if
i = 1
do
if (string(i:i+searchLen-1)==search) then
modifiedString = string(1:i-1) // substitute // replaceStr(string(i+searchLen:stringLen),search,substitute)
exit
end if
if (i+searchLen>stringLen) then
modifiedString = string
exit
end if
i = i + 1
cycle
end do
end function replaceStr
!***********************************************************************************************************************************
!***********************************************************************************************************************************
function splitStr(string,delimiter)
implicit none
character(len=*) , intent(in) :: string,delimiter
character(len=:) , allocatable :: dummyStr
type(CharVec_type), allocatable :: splitStr(:)
integer(IK) :: maxNumSplit
integer(IK) :: stringLen, delimLen, splitCounter, currentPos
dummyStr = string
delimLen = len(delimiter)
stringLen = len(dummyStr)
if (delimLen==0) then
allocate(splitStr(1))
splitStr(1)%record = string
return
end if
maxNumSplit = 1 + stringLen / delimLen
allocate(splitStr(maxNumSplit))
splitCounter = 1
loopParseString: do
if (stringLen<delimLen) then
splitStr(splitCounter)%record = dummyStr
exit loopParseString
elseif (stringLen==delimLen) then
if (dummyStr==delimiter) then
splitStr(splitCounter)%record = ""
end if
exit loopParseString
elseif (dummyStr(1:delimLen)==delimiter) then
dummyStr = dummyStr(delimLen+1:stringLen)
stringLen = len(dummyStr)
cycle loopParseString
else
currentPos = 2
loopSearchString: do
if (dummyStr(currentPos:currentPos+delimLen-1)==delimiter) then
splitStr(splitCounter)%record = dummyStr(1:currentPos-1)
if (currentPos+delimLen>stringLen) then
exit loopParseString
else
splitCounter = splitCounter + 1
dummyStr = dummyStr(currentPos+delimLen:stringLen)
stringLen = len(dummyStr)
cycle loopParseString
end if
else
currentPos = currentPos + 1
if (stringLen<currentPos+delimLen-1) then
splitStr(splitCounter)%record = dummyStr
exit loopParseString
end if
cycle loopSearchString
end if
end do loopSearchString
end if
end do loopParseString
splitStr = splitStr(1:splitCounter)
end function splitStr
!***********************************************************************************************************************************
!***********************************************************************************************************************************
pure elemental function str2num(str)
implicit none
character(len=*), intent(in) :: str
real(RK) :: str2num
read(str,*) str2num
end function str2num
!***********************************************************************************************************************************
!***********************************************************************************************************************************
end module String_mod
program readFile_prog
use String_mod, only: String_type
implicit none
! Rules: comma means decimal point. Dot means thousands separator. delimiter is ;.
character(*), parameter :: FileToRead = "5;56,67;123.456,78"
type(String_type) :: String
integer :: i
! read file
String%value = FileToRead
! split file contents into individual numbers
String%Parts = String%splitStr(String%value,";")
! count the number of integers in the file
String%nPart = size(String%Parts)
do i = 1, String%nPart
! For each number, remove the thousands separator, by replacing "." with ""
String%Parts(i)%record = String%replaceStr(String%Parts(i)%record,".","")
! now replace comma decimal symbols with regular . decimal notation
String%Parts(i)%record = String%replaceStr(String%Parts(i)%record,",",".")
! Covert the integer number from character type to integer and print it on screen
write(*,"(*(g0,:,' '))") "Number(",i,") = ", String%str2num(String%Parts(i)%record)
end do
end program readFile_prog
. ]
$gfortran -std=f2008 *.f95 -o main
$main
Number( 1 ) = 5.0000000000000000
Number( 2 ) = 56.670000000000002
Number( 3 ) = 123456.78000000000
Попробуйте использовать Resharper. Я использовал его в прошлом для рефакторинга пространств имен, на которые часто ссылаются, как полностью определенных, так и импортированных без каких-либо проблем.
Я не знаю, если это будет полезно в вашем случае.
Если вы используете такой инструмент, как ReSharper, щелкните пространство имен и нажмите Ctrl + R. Следуйте инструкциям в диалоговом окне "Переименовать пространство имен".
Похоже, вы не должны ' У меня слишком много проблем при глобальном поиске и замене на полное имя. Так что выполните поиск по всем на oldspace :: myclass и замените его газетами :: myclass. Добавление строк в начало файла тоже не так уж сложно, и вы, вероятно, могли бы заменить
using oldspace;
на
using oldspace;
using newspace;
. Конечно, такой подход сопряжен с некоторыми рисками. Довольно легко вызвать себе незаметные проблемы.
Вот сценарий Powershell , который я использовал для болезненного переименования пространства имен. В моей ситуации было около 5000 исходных файлов VB.Net и C #, интенсивно использующих общую библиотеку ( CSLA ). По причинам, не заслуживающим обсуждения, мне пришлось переименовать пространство имен Csla в CslaLegacy . С минимальными усилиями вы сможете адаптировать этот сценарий к вашим конкретным потребностям. Сценарий рекурсивно ищет в дереве исходных текстов файлы .vb и .cs. Хэш-таблица $ repValues содержит строки, которые необходимо заменить. Вариант этого сценария также можно использовать для обновления ссылок на проекты, если ваше переименование включает изменение имени сборки. Вы можете добавить вызов инструмента управления версиями для проверки файла перед изменением. Первоначально я сделал это для TFS, но обнаружил, что tf.exe медленно запускается. В конце концов, было намного быстрее просто проверить все дерево исходного кода перед запуском скрипта. Я использую редактор сценариев PowerGUI для отладки и запуска сценариев PowerShell.
$root = "c:/path/to/your/source"
cd $root
$files = Get-ChildItem -Path $root -Recurse -include *.cs,*.vb
$repValues =
@{
'using Csla;' = 'using CslaLegacy;';
'using Csla.Validation;' = 'using CslaLegacy.Validation;';
'using Csla.Data;' = 'using CslaLegacy.Data;';
'Imports Csla' = 'Imports CslaLegacy';
'Imports Csla.Validation' = 'Imports CslaLegacy.Validation';
}
$stmtsToReplace = @()
foreach ($key in $repValues.Keys) { $stmtsToReplace += $null }
$repValues.Keys.CopyTo($stmtsToReplace, 0)
foreach ($file in $files)
{
$path = [IO.Path]::Combine($file.DirectoryName, $file.Name)
$sel = Select-String -Pattern $stmtsToReplace -Path $path -l
if ($sel -ne $null)
{
write "Modifying file $path"
(Get-Content -Encoding Ascii $path) |
ForEach-Object {
$containsStmt = $false
foreach ($key in $repValues.Keys)
{
if ($_.Contains($key))
{
$_.Replace($key, $repValues[$key])
$containsStmt = $true
break
}
}
if (!$containsStmt) { $_ }
} |
Set-Content -Encoding Ascii $path
}
}
Еще одна причина перейти на c sharp. Рефакторинг исходного кода, встроенный бесплатно в VS 2008.