Скорее всего, ваше имя БД неверно, вы увидите имя сервера в VS, как «DESKTOP-0I14BKI», но если вы откроете SSMS, вы увидите DESKTOP-0I14BKI \ SQLBLAHBLAH , просто добавьте « \ SQLBLAHBLAH » (имя экземпляра) к вашему «имени сервера» в свойствах VS-соединения.
Если вы действительно хотите сделать это в Фортране, это не так уж сложно. Во-первых, давайте возьмем функцию для удаления всех вхождений .
из строки:
FUNCTION drop_stops(instr) RESULT(outstr)
CHARACTER(len=*), INTENT(in) :: instr
CHARACTER(len=:), ALLOCATABLE :: outstr
CHARACTER(len=1), DIMENSION(:), ALLOCATABLE :: str_array
ALLOCATE(str_array(LEN_TRIM(instr)))
str_array = TRANSFER(instr,str_array)
str_array = PACK(str_array,str_array /= '.')
ALLOCATE(CHARACTER(len=SIZE(str_array))::outstr)
outstr = TRANSFER(str_array,outstr)
END FUNCTION drop_stops
Я верю, что это достаточно очевидно, чтобы не нуждаться в объяснении, кроме документации каких-либо функций или утверждений, которые вы не знаком с.
Затем, придерживаясь своего исходного кода и объявив другую строковую переменную, вы можете прочитать dummy
, как вы уже это делаете, затем написать что-то вроде
dummy_without_stops = drop_stops(dummy)
, и теперь вы можете выполнить внутреннее чтение этого чтобы получить интересующие вас числа, что-то вроде
read(dummy_without_stops,*,decimal='comma') a, b, c
Обратите внимание, что подход, реализованный в drop_stops
, зависит от символов в строке, последовательно размещаемых в памяти и соответствующих одному и тому же хранилищу для символы в массиве. Я уверен, что это будет работать для символов ASCII, но не уверен насчет символов ISO_10646.
program prjRead
implicit none
integer:: a
real(8) :: b
real(8) :: c
character(18) :: header
character(18) :: cAsString
character(18) :: cWithOutStops
open (123,file = "test.csv", DECIMAL='COMMA')
read(123,*) header
read(123,*) a, &
b, &
cAsString
cWithOutStops = drop_stops(cAsString)
read(cWithOutStops,*,decimal='comma') c
write(*,*) "gives c without decimal places"
write(*,*) a,b,c
write(*,*) "********************"
write(*,*) "second try, the function drop_stops does what it
promisses. If have to feed it with the right string"
cAsString ="123.456,78"
cWithOutStops = drop_stops(cAsString)
read(cWithOutStops,*,decimal='comma') c
write(*,*) a,b,c
contains
FUNCTION drop_stops(instr) RESULT(outstr)
CHARACTER(len=*), INTENT(in) :: instr
CHARACTER(len=:), ALLOCATABLE :: outstr
CHARACTER(len=1), DIMENSION(:), ALLOCATABLE :: str_array
ALLOCATE(str_array(LEN_TRIM(instr)))
str_array = TRANSFER(instr,str_array)
str_array = PACK(str_array,str_array /= '.')
ALLOCATE(CHARACTER(len=SIZE(str_array))::outstr)
outstr = TRANSFER(str_array,outstr)
END FUNCTION drop_stops
end program prjRead
Выходные данные
дают c без десятичных разрядов 5 56.670000000000002 123456.00000000000 ********************************************************* drop_stops делает то, что обещает. Если нужно указать правильную строку 5 56.670000000000002 123456.78000000000
blockquote>Решение HighPerformanceMarks почти готово. Мне не хватает только умения проглотить число с одним куском при чтении. или я читаю 2 строки и объединяю их.
Вы не предоставили достаточно большой сэмпл из вашего входного файла. Но, по сути, вам нужно сначала разделить содержимое файла по разделителю ;
. Затем для каждого полученного вами номера строки замените все разделители тысяч .
на «» (ничего). Затем замените десятичный символ ,
нормальным десятичным обозначением .
. Вот попытка добиться этого с помощью 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