Skip to content

Commit

Permalink
Merge pull request #10279 from rouault/csv_inf_nan
Browse files Browse the repository at this point in the history
CSV: allow inf, -inf and nan as numeric values
  • Loading branch information
rouault committed Jul 6, 2024
2 parents 86e203c + 3d8b1e0 commit b08dfac
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 7 deletions.
5 changes: 5 additions & 0 deletions autotest/ogr/data/csv/inf_nan.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
id,v
1,10
2,inf
3,-inf
4,NaN
21 changes: 21 additions & 0 deletions autotest/ogr/ogr_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
# Boston, MA 02111-1307, USA.
###############################################################################

import math
import pathlib
import sys

Expand Down Expand Up @@ -3133,6 +3134,26 @@ def test_ogr_csv_force_opening(tmp_vsimem):
assert ds.GetDriver().GetDescription() == "CSV"


###############################################################################
# Test opening a CSV file with inf/nan numeric values


@gdaltest.enable_exceptions()
def test_ogr_csv_inf_nan():

ds = gdal.OpenEx("data/csv/inf_nan.csv", open_options=["AUTODETECT_TYPE=YES"])
lyr = ds.GetLayer(0)
assert lyr.GetLayerDefn().GetFieldDefn(1).GetType() == ogr.OFTReal
f = lyr.GetNextFeature()
assert f["v"] == 10.0
f = lyr.GetNextFeature()
assert f["v"] == float("inf")
f = lyr.GetNextFeature()
assert f["v"] == float("-inf")
f = lyr.GetNextFeature()
assert math.isnan(f["v"])


###############################################################################


Expand Down
20 changes: 13 additions & 7 deletions ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,10 @@ char **OGRCSVLayer::AutodetectFieldTypes(CSLConstList papszOpenOptions,
else
eOGRFieldType = OFTInteger;
}
else if (eType == CPL_VALUE_REAL)
else if (eType == CPL_VALUE_REAL ||
EQUAL(papszTokens[iField], "inf") ||
EQUAL(papszTokens[iField], "-inf") ||
EQUAL(papszTokens[iField], "nan"))
{
eOGRFieldType = OFTReal;
}
Expand Down Expand Up @@ -1466,14 +1469,16 @@ OGRFeature *OGRCSVLayer::GetNextUnfilteredFeature()
if (chComma)
*chComma = '.';
}
CPLValueType eType = CPLGetValueType(papszTokens[iAttr]);
if (eType == CPL_VALUE_INTEGER || eType == CPL_VALUE_REAL)
char *endptr = nullptr;
const double dfVal =
CPLStrtodDelim(papszTokens[iAttr], &endptr, '.');
if (endptr == papszTokens[iAttr] + strlen(papszTokens[iAttr]))
{
poFeature->SetField(iOGRField, papszTokens[iAttr]);
poFeature->SetField(iOGRField, dfVal);
if (!bWarningBadTypeOrWidth &&
(eFieldType == OFTInteger ||
eFieldType == OFTInteger64) &&
eType == CPL_VALUE_REAL)
CPLGetValueType(papszTokens[iAttr]) == CPL_VALUE_REAL)
{
bWarningBadTypeOrWidth = true;
CPLError(CE_Warning, CPLE_AppDefined,
Expand All @@ -1495,8 +1500,9 @@ OGRFeature *OGRCSVLayer::GetNextUnfilteredFeature()
nNextFID, poFieldDefn->GetNameRef());
}
else if (!bWarningBadTypeOrWidth &&
eType == CPL_VALUE_REAL &&
poFieldDefn->GetWidth() > 0)
poFieldDefn->GetWidth() > 0 &&
CPLGetValueType(papszTokens[iAttr]) ==
CPL_VALUE_REAL)
{
const char *pszDot = strchr(papszTokens[iAttr], '.');
const int nPrecision =
Expand Down

0 comments on commit b08dfac

Please sign in to comment.