PDA

View Full Version : سوال: جستجوی یک کلمه فارسی در فایل PDF با کامپوننت iTextSharp



behzadkhan
سه شنبه 15 اردیبهشت 1394, 11:27 صبح
با سلام

دوستان عزیز

هنگام جستجوی یک متن فارسی در یک فایل PDF با استفاده از کامپوننت iTextSharp متون فارسی از آخر به اول هستند و متون انگلیسی بدون مشکل می باشند.

یعنی اگر ما بخواهیم یک کلمه مثل "برنامه" را جستجو کنیم به نتیجه نمی رسیم ولی اگر آنرا برعکس یعنی "همانرب" بنویسیم به نتیجه خواهیم رسید.

حالا می خواهم کدی نوشته شود که هنگام خواند هر صفحه از فایل PDF کلمه های فارسی را بصورت اتوماتیک به حالی عادی بر گرداند.
================================================== ================================================== =====
برای تفهیم این موضوع یک عکس از آن مورد تهیه نمودم:

130895


هم چنین کد مورد نظر:

public int ReadPdfFile(string fileName, String searthText)
{
int count =0;
if (File.Exists(fileName))
{
PdfReader pdfReader = new PdfReader(fileName);

for (int page = 1; page <= pdfReader.NumberOfPages; page++)
{
ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
string currentPageText = PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy);


if (currentPageText.ToLower().Contains(searthText))
{
count++;
}
}
pdfReader.Close();
}
return count;
}


برای دانلود کامپوننت مربوطه از لینک زیر استفاده نمایید:

http://sourceforge.net/projects/itextsharp/

================================================== ===========================

همچنین اگر راه های دیگری برای اینکار وجود دارد از آن استقبال می کنم.
البته با کامپوننت Aspose به جایی نرسیدم.

با تشکر

Hamid2547
سه شنبه 15 اردیبهشت 1394, 12:01 عصر
استرینگی که برعکسه رو توی یک متغیر ذخیره کن، متغییر رو بفرست توی این فانکشن، نتیجه رو توی یک متغیر دیگه ذخیره کن.

public static string Reverse( string s )
{
char[] charArray = s.ToCharArray();
Array.Reverse( charArray );
return new string( charArray );
}

behzadkhan
سه شنبه 15 اردیبهشت 1394, 12:25 عصر
استرینگی که برعکسه رو توی یک متغیر ذخیره کن، متغییر رو بفرست توی این فانکشن، نتیجه رو توی یک متغیر دیگه ذخیره کن.

public static string Reverse( string s )
{
char[] charArray = s.ToCharArray();
Array.Reverse( charArray );
return new string( charArray );
}


با سلام

دوست عزیز

از پاسختان سپاس گذارم.

بله اکنون تمامی کلمات فارسی راست به چپ شده و می توان در آن کلمات فارسی را جستجو کرد.
اما
کلمات چپ به راست مثل کلمات انگلیسی اکنون راست به چپ شده و حالا ما نمی توانیم کلمات انگلیسی را جستجو کنیم.

در واقع ما هنگام معکوس کردن رشته باید بفهمیم که کدام کلمه راست به چپ هست و کدام کلمه چپ با راست می باشد.

فکر می کنم با استفاده از کاراکتر های کنترلی مثل "u\200E" و "u\200F" می توان در یک رشته فهمید که کدام کلمه راست به چپ و کدام چپ به راست هست و با مقایسه کردن فقط کلماتی که راست به چپ هستند را برعکس نمود.

برای تفهیم موضوع عکس زیر را با عکس پست اول بررسی کنید:
130897


با تشکر

behzadkhan
سه شنبه 15 اردیبهشت 1394, 13:37 عصر
با سلام

دوستان عزیز

روش زیر را برای حل مشکل پیدا نمودم:

ابتدا کد زیر را به برنامه اضافه می کنید:


[SuppressUnmanagedCodeSecurity]
class GdiMethods
{
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr hgdiobj);


[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint GetCharacterPlacement(IntPtr hdc, string lpString, int nCount, int nMaxExtent, [In, Out] ref GcpResults lpResults, uint dwFlags);


[DllImport("GDI32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
}


[StructLayout(LayoutKind.Sequential)]
struct GcpResults
{
public uint lStructSize;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpOutString;
public IntPtr lpOrder;
public IntPtr lpDx;
public IntPtr lpCaretPos;
public IntPtr lpClass;
public IntPtr lpGlyphs;
public uint nGlyphs;
public int nMaxFit;
}


public class UnicodeCharacterPlacement
{
const int GcpReorder = 0x0002;
GCHandle _caretPosHandle;
GCHandle _classHandle;
GCHandle _dxHandle;
GCHandle _glyphsHandle;
GCHandle _orderHandle;


public Font Font { set; get; }


public string Apply(string lines)
{
if (string.IsNullOrWhiteSpace(lines))
return string.Empty;


return Apply(lines.Split('\n')).Aggregate((s1, s2) => s1 + s2);
}


public IEnumerable<string> Apply(IEnumerable<string> lines)
{
if (Font == null)
throw new ArgumentNullException("Font is null.");


if (!hasUnicodeText(lines))
return lines;


var graphics = Graphics.FromHwnd(IntPtr.Zero);
var hdc = graphics.GetHdc();
try
{
var font = (Font)Font.Clone();
var hFont = font.ToHfont();
var fontObject = GdiMethods.SelectObject(hdc, hFont);
try
{
var results = new List<string>();
foreach (var line in lines)
results.Add(modifyCharactersPlacement(line, hdc));
return results;
}
finally
{
GdiMethods.DeleteObject(fontObject);
GdiMethods.DeleteObject(hFont);
font.Dispose();
}
}
finally
{
graphics.ReleaseHdc(hdc);
graphics.Dispose();
}
}


void freeResources()
{
_orderHandle.Free();
_dxHandle.Free();
_caretPosHandle.Free();
_classHandle.Free();
_glyphsHandle.Free();
}


static bool hasUnicodeText(IEnumerable<string> lines)
{
return lines.Any(line => line.Any(chr => chr >= '\u00FF'));
}


void initializeResources(int textLength)
{
_orderHandle = GCHandle.Alloc(new int[textLength], GCHandleType.Pinned);
_dxHandle = GCHandle.Alloc(new int[textLength], GCHandleType.Pinned);
_caretPosHandle = GCHandle.Alloc(new int[textLength], GCHandleType.Pinned);
_classHandle = GCHandle.Alloc(new byte[textLength], GCHandleType.Pinned);
_glyphsHandle = GCHandle.Alloc(new short[textLength], GCHandleType.Pinned);
}


string modifyCharactersPlacement(string text, IntPtr hdc)
{
var textLength = text.Length;
initializeResources(textLength);
try
{
var gcpResult = new GcpResults
{
lStructSize = (uint)Marshal.SizeOf(typeof(GcpResults)),
lpOutString = new String('\0', textLength),
lpOrder = _orderHandle.AddrOfPinnedObject(),
lpDx = _dxHandle.AddrOfPinnedObject(),
lpCaretPos = _caretPosHandle.AddrOfPinnedObject(),
lpClass = _classHandle.AddrOfPinnedObject(),
lpGlyphs = _glyphsHandle.AddrOfPinnedObject(),
nGlyphs = (uint)textLength,
nMaxFit = 0
};
var result = GdiMethods.GetCharacterPlacement(hdc, text, textLength, 0, ref gcpResult, GcpReorder);
return result != 0 ? gcpResult.lpOutString : text;
}
finally
{
freeResources();
}
}
}


سپس کد خواند متن را به شکل زیر تغییر می دهید:


public int ReadPdfFile(string fileName, String searthText)
{
int count =0;
if (File.Exists(fileName))
{
PdfReader pdfReader = new PdfReader(fileName);

for (int page = 1; page <= pdfReader.NumberOfPages; page++)
{
var text = PdfTextExtractor.GetTextFromPage(pdfReader, page, new LocationTextExtractionStrategy());
text = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(tex t));
text = new UnicodeCharacterPlacement
{
Font = new System.Drawing.Font("Tahoma", 12)
}.Apply(text);

if (text.ToLower().Contains(searthText))
{
count++;
}
}
pdfReader.Close();
}
return count;
}


منبع:

http://www.dotnettips.info/post/1160/%D8%A7%D8%B3%D8%AA%D8%AE%D8%B1%D8%A7%D8%AC-%D9%85%D8%AA%D9%86-%D8%A7%D8%B2-%D9%81%D8%A7%DB%8C%D9%84%E2%80%8C%D9%87%D8%A7%DB%8 C-pdf-%D8%AA%D9%88%D8%B3%D8%B7-itextsharp

با تشکر از دوستان